C ++可变参数的可变参数模板参数

时间:2017-03-14 14:27:08

标签: c++ c++11 templates variadic-templates template-specialization

拥有可变参数模板很简单,我可以对其进行专门化,因此它只会接受TStringConstant string_constant的某些char

template <typename TStringConstant, typename TValue>
class entry;

template <char... key, typename TValue>
class entry<string_constant<key...>, TValue>{}

如果我想创建一个模板类来接受TStringConstant个不同char的可变数量的entry_list<string_constant<'c','b','a'>, string_constant<'d','e','f','g'>>(); entry_list<string_constant<'c','b','a'>, string_constant<'d','e','f','g'>, string_constant<'d','e','z','z'>>(); entry_list<string_constant<'a','b','c'>>(); ,那么有没有办法做到这一点?也许有模板模板参数?

以下所有内容都有效:

entry_list<something_else<'c','b','a'>>

奖励,如果它将拒绝entry<something_else<'c','b','a'>, bool>,就像import java.lang.reflect.Field; public class SubInitProblem { public static void main(String[] args) throws IllegalAccessException { Child p = new Child(); } } class Parent { public int parentVar = 888888; public Parent() throws IllegalAccessException { this.showFields(); } public void showFields() throws IllegalAccessException { for (Field f : this.getClass().getFields()) { System.out.println(f + ": " + f.get(this)); } } } class Child extends Parent { public int childVar = 999999; public Child() throws IllegalAccessException { super(); } } 将无法编译一样。

2 个答案:

答案 0 :(得分:3)

您可以使用static_assert执行此操作。我不知道如何以友好的方式实现它,但我猜你不关心它。

所以这就是:

template <class... Args> struct entry {
    static_assert(are_string_constant<Args...>::value, "invalid template args for entry");
};

auto test()
{
  entry<string_constant<'c', 'd'>> e1; // OK
  entry<string_constant<'c', 'd'>, string_constant<'a', 'b', 'c', 'd'>> e2; // OK

  // entry<int,
  //       string_constant<'c', 'd'>,
  //       string_constant<'a', 'b', 'c', 'd'>> e3; // static_assert kicks in

  // entry<definitely_not_string_constant<'c', 'd'>,
  //       string_constant<'a', 'b', 'c', 'd'>> e4; // static_assert kicks in


}

are_string_constant的建设非常简单:

template <char... Args> struct string_constant {};
template <char... Args> struct definitely_not_string_constant {};

// --- is_string_constant -----

template <class T> struct is_string_constant : std::false_type {};

template <char... Args>
struct is_string_constant<string_constant<Args...>> : std::true_type {};

// --- are_string_constant -----    

template <class... Args> struct are_string_constant;

template <class A0, class... Args>
struct are_string_constant<A0, Args...>
     : std::integral_constant<bool, (is_string_constant<A0>::value &&
                                     are_string_constant<Args...>::value)>::type
{};

template <class T> struct are_string_constant<T> : is_string_constant<T>::type {};

在c ++ 17中,使用fold expressions可以更轻松地实现(因为您不需要are_string_constant):

template <class... Args>
struct entry {
    static_assert((... && is_string_constant<Args>::value),
                  "invalid template args for entry");
};

答案 1 :(得分:0)

我看到的真正问题是:您希望如何使用entry_list类的变量列表?

我喜欢bolov的解决方案(+1)但是,如果你接受递归解决方案,我建议使用继承。

以下是一个完整的例子

template <char ...>
struct string_constant
 { };

template <char ...>
struct something_else
 { };

template <typename ...>
class entry_list;

template <>
class entry_list<>
 { };

template <char ... keys, typename ... Scs>
class entry_list<string_constant<keys ...>, Scs ...>
   : public entry_list<Scs ...>
 { };

int main ()
 {
   entry_list<string_constant<'c','b','a'>,
              string_constant<'d','e','f','g'>>(); // compile

   entry_list<string_constant<'c','b','a'>,
              string_constant<'d','e','f','g'>,
              string_constant<'d','e','z','z'>>(); // compile

   entry_list<string_constant<'a','b','c'>>(); // compile

   //entry_list<something_else<'c','b','a'>>(); // compilation error

   //entry_list<string_constant<'c','b','a'>, bool>(); // compilation error
 }

如果您不想使用继承,可以使用static_assert()代替

template <char ... keys, typename ... Scs>
class entry_list<string_constant<keys ...>, Scs ...>
 { static_assert(sizeof(entry_list<Scs...>), "!"); };