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

时间:2012-02-01 17:51:30

标签: c++ function parameters c++11

我有以下课程模板:

template<class T, unsigned N>
class MyClass;

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

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

  1. 它由另一种类型T2(即template<class T2> void foo(..)
  2. 模板化
  3. 它接受足够的数据来构建MyClass<T,N>,但不是更少而不是更多。违反此规则会导致编译时错误。
  4. 从参数类型中推导出T2。即我希望每次都无需输入foo({a1, a2, a3})foo(a1, a2, a3)就可以拨打<double>MyClass<double,N>或类似内容。
  5. 有没有办法实现这个功能,以满足上述要求?

    我已经考虑过和/或尝试了以下解决方案:

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

4 个答案:

答案 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);

Check it

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...});
}
相关问题