C++ variadic 可变参数模板参数的数量
C++ variadic number of variadic template parameters
拥有一个可变参数模板很简单,我可以对其进行专门化,因此它只接受一个 TStringConstant
,即一些 char
的 string_constant
:
template <typename TStringConstant, typename TValue>
class entry;
template <char... key, typename TValue>
class entry<string_constant<key...>, TValue>{}
如果我想制作一个模板 class 来接受可变数量的 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>
将无法编译一样。
你可以用 static_assert
来完成。我不知道如何以 sfinae 友好的方式实现它,但我猜你不关心那个。
就是这样:
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");
};
我看到的真正问题是:您想如何使用 entry_list
class 的可变字符列表?
我喜欢 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...>), "!"); };
拥有一个可变参数模板很简单,我可以对其进行专门化,因此它只接受一个 TStringConstant
,即一些 char
的 string_constant
:
template <typename TStringConstant, typename TValue>
class entry;
template <char... key, typename TValue>
class entry<string_constant<key...>, TValue>{}
如果我想制作一个模板 class 来接受可变数量的 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>
将无法编译一样。
你可以用 static_assert
来完成。我不知道如何以 sfinae 友好的方式实现它,但我猜你不关心那个。
就是这样:
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");
};
我看到的真正问题是:您想如何使用 entry_list
class 的可变字符列表?
我喜欢 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...>), "!"); };