成员函数模板的参数数量取决于一个积分模板参数

Member function template with the number of parameters depending on an integral template parameter

本文关键字:参数 一个 函数模板 数数 成员 取决于      更新时间:2023-10-16

我有以下类模板:

template<class T, unsigned N>
class MyClass;

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

我想添加一个MyClass的成员函数模板(让我们将其命名为foo),它将满足以下要求:

  1. 它由另一种类型T2(即template<class T2> void foo(..))模板化
  2. 它接受足够的数据来构造MyClass<T,N>,但不能少也不能多。违反此规则将导致编译时错误
  3. 从参数的类型推导出CCD_ 10。也就是说,我希望可以调用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) 可变模板魔术

类似以下功能的东西会很简洁:

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的一组专门化,而不是使用这个。

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
...

第三个变体的第二个非类型参数的前缀应该是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 snapshots在模板方面有一些错误,我想,如果你用Gcc 4.6.2/1尝试它,它会起作用。

为什么不使用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.
    }
};

可能是这样的:

#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不能承诺这一点。

可能是,基于您的第三个变体,您可以从初始值设定项列表中提取第一个参数,并通过它来推断类型

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...});
}
相关文章: