Список значений перечисления во время компиляции - PullRequest
0 голосов
/ 05 июня 2018

В современном C ++ (GCC 5.1.0, так что C ++ 14, я думаю), какой самый быстрый способ передать во время компиляции список значений enum, а затем во время выполнения, проверьте, какие значения там есть?

enum foobar { foo, bar, baz };

template<????>
void f() {
  if( contains<????, foo>() )
    std::cout << "foo!";
  if( contains<????, bar>() )
    std::cout << "bar!";
  if( contains<????, baz>() )
    std::cout << "baz!";
}

f<foo,bar>();

Примечание: Это для модульных тестов, поэтому скорость и т. д. в основном не имеют значения, и основная цель состоит в том, чтобы кто-то мог ее расшифроватькто не знаком с кодом.

Ответы [ 3 ]

0 голосов
/ 05 июня 2018

Вариантный вариант.Он печатает «foo! Bar! Baz! Foo!», Как и ожидалось.

enum class foobar { foo, bar, baz };

void test() {}

template< typename F, typename... Fs >
void test( F Foo, Fs const&... args )
{
    switch( Foo )
    {
    case foobar::foo:
        std::cout << "foo!";
        break;
    case foobar::bar:
        std::cout << "bar!";
        break;
    case foobar::baz:
        std::cout << "baz!";
        break;
    }
    test( args... );
}

int main() {
    test( foobar::foo, foobar::bar, foobar::baz, foobar::foo );
}
0 голосов
/ 05 июня 2018

Я не знаю, если вы все еще заинтересованы, но ... чтобы ответить на ваш первоначальный вопрос ... если вы измените порядок аргументов шаблона для contain ... Я имею в виду

if( contains<foo, ????>() )

вместо

if( contains<????, foo>() )

ваш contains (переименован в containsFB в моих следующих примерах) может быть, начиная с C ++ 14, простой constexpr функцией

template <foobar F0, foobar ... Fs>
constexpr bool containsFB ()
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= F0 == Fs ... };

   return ret;
 }

Начиная с C ++ 17, вы также можете использовать свертывание шаблонов, и constantFB можно записать как черты типа, которые наследуются от std::true_type или std::false_type.

template <foobar F0, foobar ... Fs>
struct containsFB : public std::integral_constant<bool, ((F0 == Fs) || ...)>
 { };

Ниже приведено полноерабочий C ++ 14 пример

#include <iostream>
#include <utility>

enum foobar { foo, bar, baz };


template <foobar F0, foobar ... Fs>
constexpr bool containsFB ()
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= F0 == Fs ... };

   return ret;
 }

/* C++17 alternative
template <foobar F0, foobar ... Fs>
struct containsFB : public std::integral_constant<bool, ((F0 == Fs) || ...)>
 { };
 */

template <foobar ... Fs>
void f ()
 {
   if( containsFB<foo, Fs...>() ) std::cout << "foo!";
   if( containsFB<bar, Fs...>() ) std::cout << "bar!";
   if( containsFB<baz, Fs...>() ) std::cout << "baz!";
 }

int main ()
 {
   f<foo,bar>();
 }

Если вы хотите сделать containsFB (функцию или структуру) немного более универсальным, вы можете шаблонизировать тип значений;так что

template <typename T, T F0, T ... Fs>

вместо

template <foobar F0, foobar ... Fs>
0 голосов
/ 05 июня 2018

Вот одно предложение

#include <initializer_list>// pulled in by a lot of stuff

enum class options  { foo,bar,baz };
void test_func(options opt)
{

}
int main()
{
    auto test_vector = { options::foo, options::bar  };
    for (auto option : test_vector)
    {
        test_func(option);
    }
    return 0;
}

Немного сложнее проверить, что поставляемые тестовые векторы содержат то, что они должны содержать:

#include <initializer_list>
#include <algorithm>
#include <stdexcept>

enum class options { foo, bar, baz, wuz };
void test_func(options)
{

}

template<typename AT, typename BT>
void assert_test_vectors(AT a, BT check_these_items)
{
    for (auto item : check_these_items)
    {
        auto test = std::find(a.begin(), a.end(), item) != a.end();
        if (!test)
        {
            return throw std::runtime_error("You suck");
        }
    }
}

template<typename T>
void run_tests(T tests)
{
    const auto better_have_these = { options::foo, options::bar };
    assert_test_vectors(tests, better_have_these);
    for (auto test : tests)
    {
        test_func(test);
    }
}

int main()
{
    const auto test_vectors = { options::foo, options::wuz };
    run_tests(test_vectors);
    return 0;
}
...