2

私はこのようなことをしようとしています:

template<typename enumType,
         std::initializer_list<enumType> values,
         std::initializer_list<std::string> mappings>
struct enum_converter {
    enumType toEnum(const std::string& literal) { ... }
    std::string toString(const enumType value) { ... }
};

次のように使用したいと思います。

enum test_enum {value_a, value_b};
struct test_enum_converter : public enum_converter<
        test_enum,
        {value_a, value_b},
        {"a", "b"}> {};

GCCは私に言います:

class std::initializer_list<_Tp> is not a valid type
for a template constant parameter.

タイプに追加constしても何も変わりません。回避策または同様の解決策はありますか?

4

2 に答える 2

3

非型テンプレート パラメーターとして使用できるのは、整数型、列挙型、ポインター、および参照のみです。std::initializer_listそのどちらでもありません。

値とマッピングをテンプレート パラメータにする必要がありますか? それらをコンストラクターの通常のパラメーターにし、列挙型のみをテンプレートパラメーターとして保持するのはどうですか?

template<typename enumType>
struct enum_converter {
    enum_converter(std::initializer_list<enumType> values, std::initializer_list<std::string> mappings) : values(values), mappings(mappings)

    enumType toEnum(const std::string& literal) { ... }
    std::string toString(const enumType value) { ... }

private:
    std::initializer_list<enumType> values;
    std::initializer_list<std::string> mappings;
};

enum_converter<test_enum> test_enum_converter({...}, {...});

int main()
{
    test_enum_converter.toEnum("bla");
}

編集

インスタンスフリーの代替案は次のとおりです。

template<typename enumType>
struct enum_converter {
    static init(std::initializer_list<enumType> values, std::initializer_list<std::string> mappings)
    { s_values = values; s_mappings = mappings; }

    static enumType toEnum(const std::string& literal) { ... }
    static std::string toString(const enumType value) { ... }

private:
    static std::initializer_list<enumType> s_values;
    static std::initializer_list<std::string> s_mappings;
};

init()クラスを使用する前に一度呼び出すだけです。

特定の列挙型に対して複数のインスタンス化が必要な場合は、次のように曖昧さ回避パラメーターをテンプレートに追加できます。

template <typename enumType, typename tag>
struct enum_converter { /*as before*/ };

int main()
{
  struct data_strings;
  struct user_readable_strings;
  enum_converter<test_enum, data_strings>::init({...}, {"a", "b"});
  enum_converter<test_enum, user_readable_strings>::init({...}, {"Option A", "Option B"});
}
于 2013-06-18T12:38:12.137 に答える
1

ポインタは、定数式、つまり extern リンケージを持つオブジェクトのアドレスである場合にのみ、テンプレートの引数になることができます。次のコードは機能しますが、価値があるかどうかはあなた次第です。

typedef char const * charptype;

template <int, charptype> struct item;

template <typename ...> struct econv
{
  static constexpr charptype convert(int) { return nullptr; }
};

template <int I, charptype S, typename ...Tail>
struct econv<item<I, S>, Tail...>
{
  static constexpr charptype convert(int i)
  {
    return i == I ? S : econv<Tail...>::convert(i);
  }
};

#include <iostream>
extern char const Hello[] = "Hello";
extern char const World[] = "World";

int main()
{
    std::cout << econv< item<1, Hello>
                      , item<2, World> >::convert(2)
    << "\n";
}

文字列を匿名の名前空間に入れ、いくつかのヘルパー マクロを使用することで、このアプローチは見栄えが良くなるように少しクリーンアップされる可能性があります。

于 2013-06-18T12:36:25.283 に答える