Синтаксический сахар: x in (a,b,c)
Уважаемые коллеги,
Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
if x in (1,2,4,6,7):
print ('x is either 1,2,4,6 or 7' )
else :
print ('x is something else' )
Понятное, что можно сделать вектор, потом воспользоваться find_if и т.д. Но это уже несколько строк, а хотелось бы in-place.
Заранее спасибо!
Re: Синтаксический сахар: x in (a,b,c)
Здравствуйте, MarcoPolo, Вы писали:
MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
написать шаблонную функцию in от переменного числа аргументов?
Третий Рим должен пасть!
Re[2]: Синтаксический сахар: x in (a,b,c)
Здравствуйте, GhostCoders, Вы писали:
GC>написать шаблонную функцию in от переменного числа аргументов?
#include <iostream>
using namespace std;
template <typename T>
bool in(T value, T last)
{
if (value == last)
return true ;
return false ;
}
template <typename T, typename ... Args>
bool in(T value, T first, Args... args)
{
if (value == first)
return true ;
return in(value, args...);
}
int main()
{
if (in(5, 1, 2, 4, 6, 7))
cout << "5 in 1, 2, 4, 6, 7" << endl;
else
cout << "5 not in 1, 2, 4, 6, 7" << endl;
if (in(4, 1, 2, 4, 6, 7))
cout << "4 in 1, 2, 4, 6, 7" << endl;
else
cout << "4 not in 1, 2, 4, 6, 7" << endl;
return 0;
}
Третий Рим должен пасть!
Re: Синтаксический сахар: x in (a,b,c)
Здравствуйте, MarcoPolo, Вы писали:
MP>Уважаемые коллеги,
MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
MP>
MP>if x in (1,2,4,6,7):
MP> print ('x is either 1,2,4,6 or 7' )
MP>else :
MP> print ('x is something else' )
MP>
В виде обычной вариадик-функции можно:
http://coliru.stacked-crooked.com/a/8bb6c54baf9352b9 :
template <typename T, typename ...U>
bool in(T&& t, U&&...u) {
return ((t == u) || ...);
}
--
Re[3]: Синтаксический сахар: x in (a,b,c)
Независимо от вас написал
template <typename T>
bool in_list(T x, T v) {
return x == v;
}
template <typename T, typename ... Args>
bool in_list(T x, T first, Args... args) {
return x == first || in_list(x, args...);
}
Re: Синтаксический сахар: x in (a,b,c)
От:
jahr
Дата: 18.02.20 09:19
Оценка:
Здравствуйте, MarcoPolo, Вы писали:
Прошу прощения, затупил, не про то ответил.)
Re: Синтаксический сахар: x in (a,b,c)
Здравствуйте, MarcoPolo, Вы писали:
О, можно так:
if std::set({1,2,4,6,7}).count(x)
std::cout << "x is either 1,2,4,6 or 7" << std::endl;
Re[2]: Синтаксический сахар: x in (a,b,c)
От:
flаt
Дата: 18.02.20 09:36
Оценка:
+1
Здравствуйте, rg45, Вы писали:
R>В виде обычной вариадик-функции можно: http://coliru.stacked-crooked.com/a/8bb6c54baf9352b9 :
R>R>template <typename T, typename ...U>
R>bool in(T&& t, U&&...u) {
R> return ((t == u) || ...);
R>}
R>
Fold expressions от C++17, а ТС обозначил 14й стандарт.
Re[3]: Синтаксический сахар: x in (a,b,c)
От:
rg45
Дата: 18.02.20 09:45
Оценка:
Здравствуйте, GhostCoders, Вы писали:
GC>GC> if (value == last)
GC> return true ;
GC> return false ;
GC>
Почему бы не написать просто:
return value == last;
--
Re: Синтаксический сахар: x in (a,b,c)
Здравствуйте, MarcoPolo, Вы писали:
MP>Уважаемые коллеги,
MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
MP>[python]
MP>if x in (1,2,4,6,7):
а определение функции в хидер сунуть можно?
template <typename T>
bool in_list( const T& needle, const std::initializer_list<T>& haystack ) {
return std::find( haystack.begin(), haystack.end(), needle ) != haystack.end();
}
if ( in_list( k, {3,6,some_var,foo()} ) {
// ...
} else {
// ...
}
Re[4]: Синтаксический сахар: x in (a,b,c)
От:
rg45
Дата: 18.02.20 10:02
Оценка:
Здравствуйте, MarcoPolo, Вы писали:
MP>Независимо от вас написал
MP>MP>template <typename T>
MP>bool in_list(T x, T v) {
MP> return x == v;
MP>}
MP>template <typename T, typename ... Args>
MP>bool in_list(T x, T first, Args... args) {
MP> return x == first || in_list(x, args...);
MP>}
MP>
Для того, чтобы поддержать пустые списки, лучше написать чуть по-другому:
template <typename T>
bool in_list(T&&) {
return false ;
}
template <typename T, typename ... Args>
bool in_list(T&& x, T&& first, Args&&... args) {
return x == first || in_list(x, args...);
}
Ну и параметры лучше принимать по ссылкам, все-таки — чтобы работало и для некопируемых/неперемещаемых типов.
--
Re: Синтаксический сахар: x in (a,b,c)
Здравствуйте, MarcoPolo, Вы писали:
MP>Уважаемые коллеги,
MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
MP>
MP>if x in (1,2,4,6,7):
MP> print ('x is either 1,2,4,6 or 7' )
MP>else :
MP> print ('x is something else' )
MP>
есть целая лекция по этому поводу,
там сравниваются разные подходы и даже смотрят получившийся
ассемблер чтобы убедиться что генерируется нормальный код:
https://youtu.be/XBUXBYpEedI
Re: Синтаксический сахар: x in (a,b,c)
От:
PM
Дата: 18.02.20 20:04
Оценка:
33 (8)
Здравствуйте, MarcoPolo, Вы писали:
MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
MP>
MP>if x in (1,2,4,6,7):
MP> print ('x is either 1,2,4,6 or 7' )
MP>else :
MP> print ('x is something else' )
MP>
MP>Понятное, что можно сделать вектор, потом воспользоваться find_if и т.д. Но это уже несколько строк, а хотелось бы in-place.
Можно. Нужно только сделать бинарный оператор, аналогичный питоновскому in:
#include <algorithm>
#include <vector>
#include <array>
#include <iostream>
const struct in_op final
{
template <typename T>
struct impl
{
T const & x;
template <typename Container>
bool operator >(Container const & c) const
{
return std::find(std::begin(c), std::end(c), x) != std::end(c);
}
};
template <typename T>
friend auto operator <(T const &x, in_op)
{
return impl<T>{x};
}
} in;
int main()
{
const std::array<int , 3> a{ 1, 2, 3 };
const std::vector<int > b{ 1, 2, 3 };
const std::initializer_list<int > c{ 5, 6, 7 };
std::cout << "5 in { 1, 2, 3 } = " << std::boolalpha << (5 <in> a) << '\n' ;
std::cout << "2 in { 1, 2, 3 } = " << std::boolalpha << (2 <in> b) << '\n' ;
std::cout << "7 in { 5, 6, 7 } = " << std::boolalpha << (7 <in> c) << '\n' ;
return 0;
}
Результат запуска
https://ideone.com/wnpoqL
5 in { 1, 2, 3 } = false
2 in { 1, 2, 3 } = true
7 in { 5, 6, 7 } = true
Re: Синтаксический сахар: x in (a,b,c)
От:
B0FEE664
Дата: 18.02.20 22:47
Оценка:
Здравствуйте, MarcoPolo, Вы писали:
MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:
MP>
MP>if x in (1,2,4,6,7):
MP> print ('x is either 1,2,4,6 or 7' )
MP>else :
MP> print ('x is something else' )
MP>
MP>Понятное, что можно сделать вектор, потом воспользоваться find_if и т.д. Но это уже несколько строк, а хотелось бы in-place.
Зачем несколько строк? Пишем по месту:
#include <iostream>
#include <initializer_list>
#include <algorithm>
int main() {
int x = 7;
if (const auto a = {1,2,4,6,7}; a.end() != std::find(a.begin(), a.end(), x) )
std::cout << "x is either 1,2,4,6 or 7" << std::endl;
else
std::cout << "x is something else" << std::endl;
// your code goes here
return 0;
}
https://ideone.com/7qBtBS
А вообще есть ещё такое:
for (auto n : {1,2,4,6,7})
if ( x == n )
{
std::cout << "x is either 1,2,4,6 or 7" << std::endl;
break ;
}
Думаю этот if в C++20 можно будет записать действительно коротко.
И каждый день — без права на ошибку...
Re[2]: Синтаксический сахар: x in (a,b,c)
От:
rg45
Дата: 19.02.20 09:42
Оценка:
Здравствуйте, jahr, Вы писали:
J>О, можно так:
J>
J>if std::set({1,2,4,6,7}).count(x)
J> std::cout << "x is either 1,2,4,6 or 7" << std::endl;
J>
Поиск по списку с полным копированием списка? Причем с двойным копированием — сначала в initializer_list, затем в set — в случае если элементы списка заданы не prvalue выражениями. Ну, для простых типов, наверное, приемлемо.
--
Re[3]: Синтаксический сахар: x in (a,b,c)
От:
Аноним
Дата: 19.02.20 14:17
Оценка:
Здравствуйте, rg45, Вы писали:
J>>
J>>if std::set({1,2,4,6,7}).count(x)
J>> std::cout << "x is either 1,2,4,6 or 7" << std::endl;
J>>
R>Поиск по списку с полным копированием списка? Причем с двойным копированием — сначала в initializer_list, затем в set — в случае если элементы списка заданы не prvalue выражениями. Ну, для простых типов, наверное, приемлемо.
Есть вариант без двойного копирования, но с бустом:
if (boost::algorithm::any_of_equal(std::initializer_list<int >{1,2,4,6,7}, x))
std::cout << "x is either 1,2,4,6 or 7" << std::endl;
Re[3]: Синтаксический сахар: x in (a,b,c)
От:
jahr
Дата: 19.02.20 14:24
Оценка:
Здравствуйте, rg45, Вы писали:
R>Поиск по списку с полным копированием списка? Причем с двойным копированием — сначала в initializer_list, затем в set — в случае если элементы списка заданы не prvalue выражениями. Ну, для простых типов, наверное, приемлемо.
Это, конечно, как раз для тривиальных случаев типа описанного в вопросе, там где хоть 10 раз скопируй все туда-сюда — на производительности это не особо скажется.)
Re[4]: Синтаксический сахар: x in (a,b,c)
От:
rg45
Дата: 19.02.20 14:32
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Есть вариант без двойного копирования, но с бустом:
А>А>if (boost::algorithm::any_of_equal(std::initializer_list<int >{1,2,4,6,7}, x))
А> std::cout << "x is either 1,2,4,6 or 7" << std::endl;
А>
Заменяем "{1,2,3,4,6,7}" на "{a,b,c,d,e}" и все равно получаем копирование.
Да и назвать такое выражение "синтаксическическим сахаром" как-то язык не поворачивается. Лично мне больше по душе "in_list(x, a, b, c, d, e)".
--
Re[5]: Синтаксический сахар: x in (a,b,c)
От:
ομικρον
Дата: 19.02.20 15:01
Оценка:
Здравствуйте, rg45, Вы писали:
А>>А>>if (boost::algorithm::any_of_equal(std::initializer_list<int >{1,2,4,6,7}, x))
А>> std::cout << "x is either 1,2,4,6 or 7" << std::endl;
А>>
R>Заменяем "{1,2,3,4,6,7}" на "{a,b,c,d,e}" и все равно получаем копирование.
Это копирование и имелось в виду. Нет второго копирования в std::set.
R>Да и назвать такое выражение "синтаксическическим сахаром" как-то язык не поворачивается. Лично мне больше по душе "in_list(x, a, b, c, d, e)".
Согласен: в такой конструкции много букв.
От:
B0FEE664
Дата: 20.02.20 12:50
Оценка:
Уважаемые коллеги, а кто-нибудь может показать решение этого вопроса с помощью
ranges ?
Коротко выразить конструкцию, аналогичную питоновской:
MP>MP>if x in (1,2,4,6,7):
MP> print ('x is either 1,2,4,6 or 7' )
MP>else :
MP> print ('x is something else' )
MP>
И каждый день — без права на ошибку...
От:
Chorkov
Дата: 20.02.20 16:07
Оценка:
Здравствуйте, B0FEE664, Вы писали:
BFE>Уважаемые коллеги, а кто-нибудь может показать решение этого вопроса с помощью ranges ?
Ranges немного для другого.
С их помощью можно, например, улучшить сообшщения об ошибках. (Получать их в точке инстационирования шаблонной функции, а не в ее внутренностях.)
Но если постараться, то можно и так...
#include <iostream>
#include <vector>
#include <array>
#include <ranges>
#include <algorithm>
#include <string>
#include <concepts>
using namespace std::literals::string_literals;
// concepts-style
template <typename T, std::ranges::range Container>
requires requires (const T& value, const Container& cnt) { value==*std::begin(cnt); } // Можно как-то по проще написать?
bool in_range( const T& value, const Container& cnt )
{
return std::ranges::find( cnt, value ) != std::ranges::end( cnt );
}
// old-style
template <typename T, typename Container>
auto in_any_container( const T& value, const Container& cnt )
-> decltype( value== *std::begin(cnt) ) // hand-make constrait!
{
for ( auto & v : cnt )
if (v==value)
return true ;
return false ;
}
int main()
{
// Success cases:
std::vector<int > vect{1,2,3};
std::cout<< in_range(1, vect ) <<std::endl;
std::cout<< in_any_container(1, vect ) <<std::endl;
std::cout<< std::ranges::count( vect, 1 ) <<std::endl;
int c_array[]={1,2,3};
std::cout<< in_range(1, c_array ) <<std::endl;
std::cout<< in_any_container(1, c_array ) <<std::endl;
std::cout<< std::ranges::count( c_array, 1 ) <<std::endl;
std::cout<< in_range(1, std::initializer_list{1,2,3} ) <<std::endl;
std::cout<< in_any_container(1, std::initializer_list{1,2,3} ) <<std::endl;
std::cout<< std::ranges::count( std::initializer_list{1,2,3}, 1 ) <<std::endl;
std::cout<< in_range(1, std::array{1,2,3} ) <<std::endl;
std::cout<< in_any_container(1, std::array{1,2,3} ) <<std::endl;
std::cout<< std::ranges::count( std::array{1,2,3}, 1 ) <<std::endl;
// Error cases:
std::cout<< in_range("1" s, vect ) <<std::endl;
/*
prog.cc: In function 'int main()':
prog.cc:58:51: error: no matching function for call to 'in_range(std::__cxx11::basic_string<char>, std::vector<int>&)'
58 | std::cout<< in_range("1"s, vect ) <<std::endl;
| ^
prog.cc:14:6: note: candidate: 'bool in_range(const T&, const Container&) [with T = std::__cxx11::basic_string<char>; Container = std::vector<int>]'
14 | bool in_range( const T& value, const Container& cnt )
| ^~~~~~~~
...
*/
std::cout<< in_any_container("1" s, vect ) <<std::endl;
/*
prog.cc: In function 'int main()':
prog.cc:59:51: error: no matching function for call to 'in_any_container(std::__cxx11::basic_string<char>, std::vector<int>&)'
59 | std::cout<< in_any_container("1"s, vect ) <<std::endl;
| ^
prog.cc:23:6: note: candidate: 'template<class T, class Container> decltype ((value == (* std::begin(cnt)))) in_any_container(const T&, const Container&)'
23 | auto in_any_container( const T& value, const Container& cnt )
| ^~~~~~~~~~~~~~~~
...
*/
std::cout<< std::ranges::count( vect, "1" s ) <<std::endl;
/*
prog.cc: In function 'int main()':
prog.cc:60:51: error: no match for call to '(const std::ranges::__count_fn) (std::vector<int>&, std::__cxx11::basic_string<char>)'
60 | std::cout<< std::ranges::count( vect, "1"s ) <<std::endl;
| ^
In file included from /opt/wandbox/gcc-head/include/c++/10.0.1/algorithm:64,
from prog.cc:5:
/opt/wandbox/gcc-head/include/c++/10.0.1/bits/ranges_algo.h:369:7: note: candidate: 'template<class _Iter, class _Sent, class _Tp, class _Proj> requires (input_iterator<_Iter>) && (sentinel_for<_Sent, _Iter>) && (indirect_binary_predicate<std::ranges::equal_to, std::projected<_I1, _P1>, const _Tp*>) constexpr std::iter_difference_t<_Iter> std::ranges::__count_fn::operator()(_Iter, _Sent, const _Tp&, _Proj) const'
369 | operator()(_Iter __first, _Sent __last,
| ^~~~~~~~
*/
return 0;
}
От:
B0FEE664
Дата: 20.02.20 16:30
Оценка:
Здравствуйте, Chorkov, Вы писали:
BFE>>Уважаемые коллеги, а кто-нибудь может показать решение этого вопроса с помощью ranges ?
C>Ranges немного для другого.
Странно. Я ожидал чего-то такого:
if ( {1,2,4,6,7} | std::ranges::count(x) )
....
или
if ( ({1,2,4,6,7} | std::views::filter([x](int i){ return x == i; })).size() )
....
так или как-то так нельзя?
И каждый день — без права на ошибку...
От:
rg45
Дата: 20.02.20 19:22
Оценка:
Здравствуйте, B0FEE664, Вы писали:
BFE>Странно. Я ожидал чего-то такого:
BFE>BFE>if ( {1,2,4,6,7} | std::ranges::count(x) )
BFE> ....
BFE>
BFE>или
BFE>BFE>if ( ({1,2,4,6,7} | std::views::filter([x](int i){ return x == i; })).size() )
BFE> ....
BFE>
Это для того, чтобы дотнетчики приходили пальцами потыкать?
--
Re[3]: Синтаксический сахар: x in (a,b,c)
Здравствуйте, GhostCoders, Вы писали:
В С++17 со сверткой можно проще:
#include <iostream>
using namespace std;
template <typename T, typename ... Args>
bool in(T value, Args... args)
{
return ((value == args) || ...);
}
int main()
{
if (in(5, 1, 2, 4, 6, 7))
cout << "5 in 1, 2, 4, 6, 7" << endl;
else
cout << "5 not in 1, 2, 4, 6, 7" << endl;
if (in(4, 1, 2, 4, 6, 7))
cout << "4 in 1, 2, 4, 6, 7" << endl;
else
cout << "4 not in 1, 2, 4, 6, 7" << endl;
return 0;
}
Здравствуйте, B0FEE664, Вы писали:
BFE>Уважаемые коллеги, а кто-нибудь может показать решение этого вопроса с помощью ranges ?
https://godbolt.org/z/rzD67Z
#include "range/v3/algorithm/contains.hpp"
#include <array>
int main() {
if ( ranges::contains(std::array{1,2,3,4,5,6}, 42) ) {
return 0;
}
return 1;
}
От:
andyp
Дата: 21.02.20 08:59
Оценка:
Здравствуйте, Voivoid, Вы писали:
V>V>#include "range/v3/algorithm/contains.hpp"
V>#include <array>
V>int main() {
V> if ( ranges::contains(std::array{1,2,3,4,5,6}, 42) ) {
V> return 0;
V> }
V> return 1;
V>}
V>
Порадовало, что это компилятор до return 1 смог оптимизировать.
От:
rg45
Дата: 21.02.20 09:55
Оценка:
Здравствуйте, andyp, Вы писали:
A>Порадовало, что это компилятор до return 1 смог оптимизировать.
Вот так почестнее будет:
https://godbolt.org/z/irQRU9
int main() {
int x {};
std::cin >> x;
if ( ranges::contains(std::array{1,2,3,4,5,6}, x) ) {
return 0;
}
return 1;
}
P.S. Ну и для сравнения:
https://godbolt.org/z/2nTHxD
template <typename T, typename ...U>
bool in_list(T&& t, U&&...u) {
return ((t == u) || ...);
}
int main() {
int x {};
std::cin >> x;
if ( in_list(x,1,2,3,4,5,6) ) {
return 0;
}
return 1;
}
--
От:
andyp
Дата: 21.02.20 10:21
Оценка:
+1
Здравствуйте, rg45, Вы писали:
R>P.S. Ну и для сравнения:
Тоже читерство. Циферки подряд
Но, кстати, работа оптимизатора и тут впечатляет.
От:
B0FEE664
Дата: 21.02.20 12:40
Оценка:
Здравствуйте, Voivoid, Вы писали:
BFE>>Уважаемые коллеги, а кто-нибудь может показать решение этого вопроса с помощью ranges ?
V>https://godbolt.org/z/rzD67Z
V>V>#include "range/v3/algorithm/contains.hpp"
V>#include <array>
V>int main() {
V> if ( ranges::contains(std::array{1,2,3,4,5,6}, 42) ) {
V> return 0;
V> }
V> return 1;
V>}
V>
Не понятно зачем нужен std::array, должно ведь и так работать: ranges::contains({1,2,3,4,5,6}, 42). Или нет?
И каждый день — без права на ошибку...
От:
rg45
Дата: 21.02.20 13:02
Оценка:
Здравствуйте, B0FEE664, Вы писали:
BFE>Не понятно зачем нужен std::array, должно ведь и так работать: ranges::contains({1,2,3,4,5,6}, 42). Или нет?
Это зависит от того, как объявлен параметр. Если просто T&& или const T&, то не выведется.
--
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить