具有参数数量的成员函数模板,具体取决于整数模板参数

p12*_*p12 12 c++ parameters function c++11

我有以下类模板:

template<class T, unsigned N>
class MyClass;
Run Code Online (Sandbox Code Playgroud)

其中T是某种类型的,N-多个组件.可以使用MyClass{a1, a2, a3}参数数量等于的位置初始化类N.

我想添加一个符合以下要求的成员函数模板(让我们命名foo)MyClass:

  1. 它是由另一种类型T2(即template<class T2> void foo(..))
  2. 它接受足够的数据来构建MyClass<T,N>,但不是更少而不是更多.违反此规则会导致编译时错误.
  3. 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
Run Code Online (Sandbox Code Playgroud)

原则上不能工作,因为支撑的初始化列表是非推导的上下文,因此它们不能推导出任何类型.这很不幸,如果有效,我会很高兴.

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);
Run Code Online (Sandbox Code Playgroud)

但是,我无法让它工作 - T2仍然无法推断.也许有人知道为什么?我使用了GCC4.7 20120121快照.

4)丑陋的一个

本质上这与上面的相同,只是针对不同的N扩展为几个重载.我最好重新实现MyClass作为不同Ns的一组特化,而不是使用这个.

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
...
Run Code Online (Sandbox Code Playgroud)

ken*_*ytm 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.
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 使用static_assert有一点需要注意:重载解析仍然可以选择此函数,即使它不应该.使用enable_if可以完全消除重载.例如,考虑我们还有非模板化的`foo(int,int,int)`的情况.然后,如果我们有`MyClass <int,2> a`,调用`a.foo(0.5,0.5,0.5)`会选择不正确的重载并失败. (9认同)

Mr.*_*bis 9

你的第三个变种的第二个非类型参数应该有前缀typename不是class :

template<class...T2, typename std::enable_if<sizeof...(T2) == N, int>::type = 0>
void foo(T2... args);
..
foo(1,2,3);
Run Code Online (Sandbox Code Playgroud)

核实

Gcc 4.7.0快照有一些模板的错误我想,如果你用gcc 4.6.2/1尝试它应该工作.