Синтаксический сахар: x in (a,b,c)
От: MarcoPolo  
Дата: 18.02.20 08:59
Оценка:
Уважаемые коллеги,

Можно ли в 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.

Заранее спасибо!
c++ find value in collection inplace
Re: Синтаксический сахар: x in (a,b,c)
От: GhostCoders Россия  
Дата: 18.02.20 09:02
Оценка:
Здравствуйте, MarcoPolo, Вы писали:

MP>Можно ли в C++ 14 как-нибудь (коротко) выразить конструкцию, аналогичную питоновской:

написать шаблонную функцию in от переменного числа аргументов?
Третий Рим должен пасть!
Re[2]: Синтаксический сахар: x in (a,b,c)
От: GhostCoders Россия  
Дата: 18.02.20 09:07
Оценка: 7 (2)
Здравствуйте, 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;
}
Третий Рим должен пасть!
Отредактировано 18.02.2020 9:10 GhostCoders . Предыдущая версия . Еще …
Отредактировано 18.02.2020 9:09 GhostCoders . Предыдущая версия .
Re: Синтаксический сахар: x in (a,b,c)
От: rg45 СССР  
Дата: 18.02.20 09:17
Оценка: 7 (2)
Здравствуйте, 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)
От: MarcoPolo  
Дата: 18.02.20 09:18
Оценка:
Независимо от вас написал

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, Вы писали:

Прошу прощения, затупил, не про то ответил.)
Отредактировано 18.02.2020 9:22 jahr . Предыдущая версия .
Re: Синтаксический сахар: x in (a,b,c)
От: jahr  
Дата: 18.02.20 09:30
Оценка: 13 (3) +2 -1
Здравствуйте, 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)
От: K13 http://akvis.com
Дата: 18.02.20 09:50
Оценка:
Здравствуйте, 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)
От: Zhendos  
Дата: 18.02.20 10:17
Оценка: 3 (1) +1
Здравствуйте, 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)".
--
Отредактировано 19.02.2020 14:33 rg45 . Предыдущая версия .
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)".


Согласен: в такой конструкции много букв.
Re: ranges ?
От: 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>
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.