我有以下课程模板:
template<class T, unsigned N>
class MyClass;
其中T
是某种类型,N
- 组件数量。可以使用MyClass{a1, a2, a3}
初始化类,其中参数的数量等于N
。
我想添加符合以下要求的foo
成员函数模板(我们将其命名为MyClass
):
T2
(即template<class T2> void foo(..)
)MyClass<T,N>
,但不是更少而不是更多。违反此规则会导致编译时错误。T2
。即我希望每次都无需输入foo({a1, a2, a3})
或foo(a1, a2, a3)
就可以拨打<double>
或MyClass<double,N>
或类似内容。有没有办法实现这个功能,以满足上述要求?
我已经考虑过和/或尝试了以下解决方案:
1)明显的一个:
...
template<class T2>
void foo(MyClass<T2, N> arg);
...
a.foo({1,2,3}); //compile-time error
原则上无法工作,因为支持的初始化列表是非推断的上下文,因此它们无法推断任何类型。这很不幸,如果能奏的话,我会很高兴。
2) initializer_list
原则上无法工作,因为它无法在编译时检查参数的数量。
3) Variadic模板魔法
以下功能之类的东西会很整洁:
template<class...T2, class std::enable_if<sizeof...(T2) == N, int>::type = 0>
void foo(T2... args);
..
foo(1,2,3);
然而,我无法让它工作 - T2仍无法推断。也许有人知道为什么?我使用了GCC4.7 20120121快照。
4)丑陋的
本质上这与上面的相同,只是针对不同的N扩展为几个重载。我最好重新实现MyClass
作为不同N
s的一组特化而不是使用这个。
template<class T2, class std::enable_if<N == 1, int>::type = 0>
void fun(T2 a1); //if N == 1
template<class T2, ..>
void fun(T2 a1, T2 a2); //if N == 2
template<class T2, ..>
void fun(T2 a1, T2 a2, T2 a3); //if N == 3
...
答案 0 :(得分:10)
为什么不使用static_assert
?
template <typename T, size_t N>
class MyClass
{
public:
template <typename... Args>
void foo(Args&&... args)
{
static_assert(sizeof...(Args) == N, "Wrong number of arguments.");
// Rest of the implementation.
}
};
答案 1 :(得分:9)
您的第三个变体的第二个非类型参数应该有前缀typename
而不是class
:
template<class...T2, typename std::enable_if<sizeof...(T2) == N, int>::type = 0>
void foo(T2... args);
..
foo(1,2,3);
Gcc 4.7.0快照有一些模板的错误,我想,如果你用gcc 4.6.2 / 1尝试它,它应该可以工作。
答案 2 :(得分:1)
也许是这样的:
#include <utility>
#include <type_traits>
template <typename T, unsigned int N>
class MyClass
{
template <typename ...Args>
typename std::enable_if<std::is_constructible<MyClass<T, N>, Args...>::value>::type
foo(Args &&... args)
{
// for example:
MyClass<T, N> m(std::forward<Args>(args)...);
// ...
}
};
仅当MyClass
具有直接接受相关参数的构造函数(如MyClass(A1, A2, A3)
)时才会起作用,但如果MyClass
具有需要的构造函数,我认为它不起作用初始化列表,如果MyClass
是需要大括号初始化的聚合,它也不会起作用。
也就是说,MyClass
可能可能接受初始化列表,因为您说它必须采用精确的N
参数, IL无法承诺。
答案 3 :(得分:1)
根据您的第三个变体,您可以从初始化列表中提取第一个参数并通过它推导出类型
template<class U, class...T2, class std::enable_if<sizeof...(T2) == N-1, int>::type = 0>
void foo(U u, T2... args)
{
MyClass<U, N>({u, args...});
}