определить наличие элемента в compile time списке
От: B0FEE664  
Дата: 22.05.20 22:21
Оценка:
Я помню, что здесь на форуме было видео где описывалась решение следующей задачи:
есть некоторое количество констант. Как красиво и эффективно написать выражение, которое будет проверять наличие некоторого значения в этом списке.
Видео найти мне не удалось, поэтому я набросал два решения:

enum class Color
{
  eRed, eBlue, eYellow
};


template<class T, T ...TArgs>
struct StaticEnumSet;

template<class T, T t>
struct StaticEnumSet<T, t>
{
  static inline bool has(T x) noexcept
  {
    return t == x;
  };
};


template<class T, T t, T ...TArgs>
struct StaticEnumSet<T, t, TArgs...>
{
  static inline bool has(T x) noexcept
  {
    return t == x || StaticEnumSet<T, TArgs...>::has(x);
  };
};

Color x = Color::eYellow;
StaticEnumSet<Color, Color::eRed, Color::eBlue>::has(x);

и
template <class... Args>
auto one_of(Args... args)
{
  return [args...](auto x) { return ((args == x) || ...);};
}

bool bNo  = one_of(Color::eRed, Color::eBlue)(x);
bool bYes = one_of(Color::eRed, Color::eYellow, Color::eBlue)(x);


но мне кажется, что уже должно быть что-то более продуманное. Подскажите?
И каждый день — без права на ошибку...
Re: определить наличие элемента в compile time списке
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 23.05.20 03:00
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Как красиво и эффективно написать выражение


Как у Вас язык поворачивается называть решения, получаемые с помощью очевидных костылей, "красивыми"? Разве только иметь в виду красоту самих костылей...
Re: определить наличие элемента в compile time списке
От: vopl Россия  
Дата: 23.05.20 07:19
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>есть некоторое количество констант. Как красиво и эффективно написать выражение, которое будет проверять наличие некоторого значения в этом списке.

template<int... Constants>
int is220InConstants()
{
    return ((220 == Constants) || ...); // OK
}
Re[2]: определить наличие элемента в compile time списке
От: B0FEE664  
Дата: 23.05.20 10:41
Оценка:
Здравствуйте, vopl, Вы писали:

BFE>>есть некоторое количество констант. Как красиво и эффективно написать выражение, которое будет проверять наличие некоторого значения в этом списке.

V>
V>template<int... Constants>
V>int is220InConstants()
V>{
V>    return ((220 == Constants) || ...); // OK
V>}
V>


Не, константы могут быть произвольного типа:

enum class Color
{
  eRed, eBlue, eYellow
};

one_of(Color::eRed, Color::eBlue)(x);
И каждый день — без права на ошибку...
Re[2]: определить наличие элемента в compile time списке
От: B0FEE664  
Дата: 23.05.20 10:43
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>Как красиво и эффективно написать выражение

ЕМ>Как у Вас язык поворачивается называть решения, получаемые с помощью очевидных костылей, "красивыми"? Разве только иметь в виду красоту самих костылей...

Ну мне же они не нравятся, вот я и спрашиваю: как надо?
И каждый день — без права на ошибку...
Re[3]: определить наличие элемента в compile time списке
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 23.05.20 10:48
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Ну мне же они не нравятся, вот я и спрашиваю: как надо?


В том и фишка, что без костылей такое никак невозможно. Но принято считать, что решение подобных задач через рекурсивные шаблоны как раз предельно изящно и элегантно.
Re: определить наличие элемента в compile time списке
От: LaptevVV Россия  
Дата: 23.05.20 14:51
Оценка:
Списки типов в Шаблонах... смотрел?
Если устроить параллельно 2 списка: список типов и список констант?
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: определить наличие элемента в compile time списке
От: Voivoid Россия  
Дата: 23.05.20 18:57
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>
BFE>template <class... Args>
BFE>auto one_of(Args... args)
BFE>{
BFE>  return [args...](auto x) { return ((args == x) || ...);};
BFE>}
BFE>


А чем свой же вариант не нравится? Выглядит вполне идиоматично.

В стандартной библиотеке пока нет ничего для работы с гетерогенными последовательностями. Могу вариант с использованием boost::hana предложить

https://wandbox.org/permlink/C2DFOXnk8DMtkmYe


constexpr auto colors = boost::hana::make_tuple(Color::eRed, Color::eBlue);
std::cout << boost::hana::contains(colors, Color::eYellow) << std::endl;
Re[4]: определить наличие элемента в compile time списке
От: Voivoid Россия  
Дата: 23.05.20 19:11
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, B0FEE664, Вы писали:


BFE>>Ну мне же они не нравятся, вот я и спрашиваю: как надо?


ЕМ>В том и фишка, что без костылей такое никак невозможно. Но принято считать, что решение подобных задач через рекурсивные шаблоны как раз предельно изящно и элегантно.


Начиная с 11-го стандарта необходимость в подобном сильно сократилась, а с появлением C++17 и fold expressions так вообще почти сошла не нет.
Re[5]: определить наличие элемента в compile time списке
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 24.05.20 04:00
Оценка:
Здравствуйте, Voivoid, Вы писали:

V>Начиная с 11-го стандарта необходимость в подобном сильно сократилась, а с появлением C++17 и fold expressions так вообще почти сошла не нет.


По большому счету, это тоже костыли. По уму, нужны универсальные языковые средства для мало-мальски интеллектуальной обработки табличных/строковых данных на этапе компиляции, по типу макропроцессора.
Re[3]: определить наличие элемента в compile time списке
От: vopl Россия  
Дата: 24.05.20 18:36
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>есть некоторое количество констант. Как красиво и эффективно написать выражение, которое будет проверять наличие некоторого значения в этом списке.

V>>
V>>template<int... Constants>
V>>int is220InConstants()
V>>{
V>>    return ((220 == Constants) || ...); // OK
V>>}
V>>


BFE>Не, константы могут быть произвольного типа


не обращай внимания на int, абстрагируйся от него . Воспринимай это лишь как один из примеров "выражения, которое будет проверять наличие некоторого значения в этом списке".

ЗЫ Я только сейчас заметил, что в твоем стартовом сообщении это "выражение" есть . Присоединяюсь к вопросу Voivoid, а действительно, чем оно не нравится?
Re[2]: определить наличие элемента в compile time списке
От: vopl Россия  
Дата: 24.05.20 20:15
Оценка: 2 (1)
Здравствуйте, Voivoid, Вы писали:

V>В стандартной библиотеке пока нет ничего для работы с гетерогенными последовательностями.


Так а зачем библиотека, сам язык позволяет жеж

template <class... Args>
constexpr auto one_of(Args... args)
{
  return [args...](auto x) { return ((args == x) || ...);};
}

int main()
{
    enum {twenty = 20};

    static_assert(one_of('a', 2.2, twenty)(20.0));
    static_assert(one_of('a', 2.2, twenty)((int)'a'));
    static_assert(!one_of('a', 2.2, twenty)(36.6f));

    return 0;
}
Re[6]: определить наличие элемента в compile time списке
От: kov_serg Россия  
Дата: 24.05.20 21:14
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, Voivoid, Вы писали:


V>>Начиная с 11-го стандарта необходимость в подобном сильно сократилась, а с появлением C++17 и fold expressions так вообще почти сошла не нет.


ЕМ>По большому счету, это тоже костыли. По уму, нужны универсальные языковые средства для мало-мальски интеллектуальной обработки табличных/строковых данных на этапе компиляции, по типу макропроцессора.


Таки что мешает вызывать генераторы кода на любых скриптах для интеллектуальной обработки кода (хоть нейросети на питоне)
  например так
#!/usr/bin/lua

function gen_tokens(list,prm)
    prm=prm or {}
    prm.prefix=prm.prefix or "tk"
    prm.name=prm.name or "tokens"
    prm.filename=prm.filename or prm.name
    prm.namefilter=function(name)
        return name:sub(1,1):upper()..name:sub(2)
    end
    local gen,tab={},{}
    list:gsub("(%S+)",function(name) table.insert(tab,{name=name}) end)
    table.sort(tab,function(a,b) return a.name<b.name end)
    local id=0 for k,v in pairs(tab) do v.id=id id=id+1 end
    function gen.enum()
        print[[enum {]]
        for k,v in pairs(tab) do
            print("\t"..prm.prefix..prm.namefilter(v.name)..",")
        end
        print("\t"..prm.prefix.."_MAX")
        print("};")
        print("extern const char* "..prm.name.."["..prm.prefix.."_MAX];")
    end
    function gen.tochars()
        print("const char* "..prm.name.."["..prm.prefix.."_MAX]={")
        for k,v in pairs(tab) do
            local sep=',' if k==#tab then sep='' end
            print('\t"'..v.name..'"'..sep)
        end
        print[[};]]
    end    
    function gen.header()
        print("// "..prm.filename..".h")
        print("#pragma once")
        print()
        gen.enum()
        print()
        return gen
    end
    function gen.source()
        print("// "..prm.filename..".c")
        print('#include "'..prm.filename..'.h"')
        print()
        gen.tochars()
        return gen
    end
    return gen
end

gen_tokens([[ zoo ape if then else begin end
function switch case return throw public class ]],{
name='mytokens'
})
.header()
.source()

// mytokens.h
#pragma once

enum {
    tkApe,
    tkBegin,
    tkCase,
    tkClass,
    tkElse,
    tkEnd,
    tkFunction,
    tkIf,
    tkPublic,
    tkReturn,
    tkSwitch,
    tkThen,
    tkThrow,
    tkZoo,
    tk_MAX
};
extern const char* mytokens[tk_MAX];

// mytokens.c
#include "mytokens.h"

const char* mytokens[tk_MAX]={
    "ape",
    "begin",
    "case",
    "class",
    "else",
    "end",
    "function",
    "if",
    "public",
    "return",
    "switch",
    "then",
    "throw",
    "zoo"
};

Зафигачить сортировку на шаблонах тоже наверное можно, но зачем если добиться требуемого результата можно более простыми средствами?
  или так
function bin9(x,r) r=""
    for i=0,8 do
        if x>>(8-i)&1== 0 then r=r..'_' else r=r..'X' end
    end
    return r
end

print[[
// bin8.h
enum {]]
line=""
for k=0,255 do
    line=line..bin9(k)
    if k<255 then line=line.."," end
    if k&7==7 then print(line) line="" end
end
print("};")

print[[
// example.c
#include "bin8.h"

unsigned char letter_A[8]={
 _________,
 ___XXXX__,
 __X____X_,
 __X____X_,
 __XXXXXX_,
 __X____X_,
 __X____X_,
 _________
};

]]

// bin8.h
enum {
_________,________X,_______X_,_______XX,______X__,______X_X,______XX_,______XXX,
_____X___,_____X__X,_____X_X_,_____X_XX,_____XX__,_____XX_X,_____XXX_,_____XXXX,
____X____,____X___X,____X__X_,____X__XX,____X_X__,____X_X_X,____X_XX_,____X_XXX,
____XX___,____XX__X,____XX_X_,____XX_XX,____XXX__,____XXX_X,____XXXX_,____XXXXX,
___X_____,___X____X,___X___X_,___X___XX,___X__X__,___X__X_X,___X__XX_,___X__XXX,
___X_X___,___X_X__X,___X_X_X_,___X_X_XX,___X_XX__,___X_XX_X,___X_XXX_,___X_XXXX,
___XX____,___XX___X,___XX__X_,___XX__XX,___XX_X__,___XX_X_X,___XX_XX_,___XX_XXX,
___XXX___,___XXX__X,___XXX_X_,___XXX_XX,___XXXX__,___XXXX_X,___XXXXX_,___XXXXXX,
__X______,__X_____X,__X____X_,__X____XX,__X___X__,__X___X_X,__X___XX_,__X___XXX,
__X__X___,__X__X__X,__X__X_X_,__X__X_XX,__X__XX__,__X__XX_X,__X__XXX_,__X__XXXX,
__X_X____,__X_X___X,__X_X__X_,__X_X__XX,__X_X_X__,__X_X_X_X,__X_X_XX_,__X_X_XXX,
__X_XX___,__X_XX__X,__X_XX_X_,__X_XX_XX,__X_XXX__,__X_XXX_X,__X_XXXX_,__X_XXXXX,
__XX_____,__XX____X,__XX___X_,__XX___XX,__XX__X__,__XX__X_X,__XX__XX_,__XX__XXX,
__XX_X___,__XX_X__X,__XX_X_X_,__XX_X_XX,__XX_XX__,__XX_XX_X,__XX_XXX_,__XX_XXXX,
__XXX____,__XXX___X,__XXX__X_,__XXX__XX,__XXX_X__,__XXX_X_X,__XXX_XX_,__XXX_XXX,
__XXXX___,__XXXX__X,__XXXX_X_,__XXXX_XX,__XXXXX__,__XXXXX_X,__XXXXXX_,__XXXXXXX,
_X_______,_X______X,_X_____X_,_X_____XX,_X____X__,_X____X_X,_X____XX_,_X____XXX,
_X___X___,_X___X__X,_X___X_X_,_X___X_XX,_X___XX__,_X___XX_X,_X___XXX_,_X___XXXX,
_X__X____,_X__X___X,_X__X__X_,_X__X__XX,_X__X_X__,_X__X_X_X,_X__X_XX_,_X__X_XXX,
_X__XX___,_X__XX__X,_X__XX_X_,_X__XX_XX,_X__XXX__,_X__XXX_X,_X__XXXX_,_X__XXXXX,
_X_X_____,_X_X____X,_X_X___X_,_X_X___XX,_X_X__X__,_X_X__X_X,_X_X__XX_,_X_X__XXX,
_X_X_X___,_X_X_X__X,_X_X_X_X_,_X_X_X_XX,_X_X_XX__,_X_X_XX_X,_X_X_XXX_,_X_X_XXXX,
_X_XX____,_X_XX___X,_X_XX__X_,_X_XX__XX,_X_XX_X__,_X_XX_X_X,_X_XX_XX_,_X_XX_XXX,
_X_XXX___,_X_XXX__X,_X_XXX_X_,_X_XXX_XX,_X_XXXX__,_X_XXXX_X,_X_XXXXX_,_X_XXXXXX,
_XX______,_XX_____X,_XX____X_,_XX____XX,_XX___X__,_XX___X_X,_XX___XX_,_XX___XXX,
_XX__X___,_XX__X__X,_XX__X_X_,_XX__X_XX,_XX__XX__,_XX__XX_X,_XX__XXX_,_XX__XXXX,
_XX_X____,_XX_X___X,_XX_X__X_,_XX_X__XX,_XX_X_X__,_XX_X_X_X,_XX_X_XX_,_XX_X_XXX,
_XX_XX___,_XX_XX__X,_XX_XX_X_,_XX_XX_XX,_XX_XXX__,_XX_XXX_X,_XX_XXXX_,_XX_XXXXX,
_XXX_____,_XXX____X,_XXX___X_,_XXX___XX,_XXX__X__,_XXX__X_X,_XXX__XX_,_XXX__XXX,
_XXX_X___,_XXX_X__X,_XXX_X_X_,_XXX_X_XX,_XXX_XX__,_XXX_XX_X,_XXX_XXX_,_XXX_XXXX,
_XXXX____,_XXXX___X,_XXXX__X_,_XXXX__XX,_XXXX_X__,_XXXX_X_X,_XXXX_XX_,_XXXX_XXX,
_XXXXX___,_XXXXX__X,_XXXXX_X_,_XXXXX_XX,_XXXXXX__,_XXXXXX_X,_XXXXXXX_,_XXXXXXXX
};
// example.c
#include "bin8.h"

unsigned char letter_A[8]={
 _________,
 ___XXXX__,
 __X____X_,
 __X____X_,
 __XXXXXX_,
 __X____X_,
 __X____X_,
 _________
};
Re[7]: определить наличие элемента в compile time списке
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.05.20 03:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Таки что мешает вызывать генераторы кода на любых скриптах


Принципиально — ничто не мешает. Но с таким подходом можно отвечать так на любые предложения об улучшении языка. Будь в числе сторонников C++ большинство любителей внешней обработки, язык мог бы замерзнуть на уровне "C с классами".
Re: определить наличие элемента в compile time списке
От: PM  
Дата: 25.05.20 05:37
Оценка: 6 (1)
Здравствуйте, B0FEE664, Вы писали:

С non-type template parameters выглядит немного короче: http://coliru.stacked-crooked.com/a/12af4c9278c00814
#include <iostream>

template<auto value, decltype(value)... values>
bool one_of(decltype(value) x)
{
    return (x == value) || ((x == values) || ...);
}

template<auto... values>
bool any_of(auto x)
{
    return ((x == values) || ...);
}

int main()
{
    enum class color { red, green, blue };
    std::cout << one_of<color::red, color::green>(color::red) << std::endl;
  
  std::cout << one_of<1, 2, 3, 4, 5, 6, 7, 8, 0>(10) << std::endl;
    //compile error: std::cout << one_of<0, 1>(color::red) << std::endl;
    
    std::cout << any_of<99, 'a', true, false>(0) << std::endl;    
}
Re[8]: определить наличие элемента в compile time списке
От: kov_serg Россия  
Дата: 25.05.20 12:10
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

_>>Таки что мешает вызывать генераторы кода на любых скриптах


ЕМ>Принципиально — ничто не мешает. Но с таким подходом можно отвечать так на любые предложения об улучшении языка. Будь в числе сторонников C++ большинство любителей внешней обработки, язык мог бы замерзнуть на уровне "C с классами".

И чего в этом плохого? Как бы задачу надо разбивать на простые максимально не связаные подзадачи. А в C++ идут в другим путём, надо всё и сразу, тем самым наращивают сложность. Вместо решения практических вопросов, строят красивый фрактал.
Re[6]: определить наличие элемента в compile time списке
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 25.05.20 12:12
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

V>>Начиная с 11-го стандарта необходимость в подобном сильно сократилась, а с появлением C++17 и fold expressions так вообще почти сошла не нет.


ЕМ>По большому счету, это тоже костыли. По уму, нужны универсальные языковые средства для мало-мальски интеллектуальной обработки табличных/строковых данных на этапе компиляции, по типу макропроцессора.


Маломальских будет мало. Захочется больше. В итоге захочется того же C++, только компайл тайма. В принципе, constexpr куда-то туда и идет
Маньяк Робокряк колесит по городу
Re[9]: определить наличие элемента в compile time списке
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.05.20 15:09
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Как бы задачу надо разбивать на простые максимально не связаные подзадачи. А в C++ идут в другим путём, надо всё и сразу, тем самым наращивают сложность. Вместо решения практических вопросов, строят красивый фрактал.


В С++ не просто наращивают сложность — они делают это "не ортогонально". То есть, чрезмерно перегружают с одних сторон, оставляя откровенное убожество с других. В основе-то лежала идея поддержки языком набора простых и довольно независимых конструкций, из которых можно наворачивать значительные по сложности программы. А с некоторых пор взяли направление на наращивание сложности отдельных конструкций, которые сами по себе довольно тяжеловесны. В итоге одним не хватает простых возможностей, а другие годами не могут уяснить, как оно устроены и работают навороченные.

Я уже не раз говорил, что имей C++ достаточно простой, но "ортогональный" другим языковым средствам набор метасредств для обработки основных элементов языка (литералов, типов, классов/объектов, списков инициализации и т.п.), шаблонам можно было бы оставить их основную задачу типонезависимости, а вместо тех уродливых конструкций, что сейчас почитаются верхом изящества, использовать на порядок более простые, понятные и масштабируемые.
Re[7]: определить наличие элемента в compile time списке
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 25.05.20 15:15
Оценка:
Здравствуйте, Marty, Вы писали:

M>Маломальских будет мало. Захочется больше. В итоге захочется того же C++, только компайл тайма.


Тут вполне уместно было бы сравнение с системой команд процессора. Какой-нибудь PDP-11 в базовом варианте не имел даже умножения, но это ничуть не мешало ему исполнять многозадачные ОС. Его можно сравнить с C. Какой-нибудь VAX или P5 можно сравнить с C++. По ходу развития добавлялись команды поддержки новых сущностей, но они не приводили к заметному перекосу. Если кому-то захочется иметь в процессоре общего назначения команду вычисления факториала или перемножения матриц, его справедливо и обоснованно пошлют, ибо это уже запредельно. А современная эволюция C++ уж очень сильно на это похожа.

M>В принципе, constexpr куда-то туда и идет


Сам по себе constexpr, безусловно, хорош и полезен. Но вот создание сложных конструкций для решения сугубо частных задач — не есть правильно.
Re[2]: определить наличие элемента в compile time списке
От: B0FEE664  
Дата: 26.05.20 20:40
Оценка:
Здравствуйте, PM, Вы писали:

PM>
PM>template<auto value, decltype(value)... values>
PM>bool one_of(decltype(value) x)
PM>{
PM>    return (x == value) || ((x == values) || ...);
PM>}
PM>


Спасибо, это то, что я хотел.
И каждый день — без права на ошибку...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.