如何参数化构造函数的参数个数?

时间:2015-06-18 20:48:46

标签: c++ templates c++11 constructor

我想在模板类构造函数中接受多个参数(此数字在模板参数中定义)。我不能使用initializer_list,因为据我所知,我无法在编译时断言它的大小。

我尝试了什么

我的第一次尝试是使用std :: array作为参数:

template<size_t s>
class foo {
  int v[s];
public:
  foo(std::array<int, s>) {/*...*/}
};

然而,这迫使我像这样初始化(即使构造函数不是explicit):

foo<4> a{{1,2,3,4}} // Two brackets.

我认为可能有一些模板魔术(可变参数模板?),但我甚至无法弄清楚在构造函数中使用的正确语法。我不能递归地调用构造函数...可以吗?

我试着寻找std::array的构造函数的定义(因为它不允许比数组大小更多的参数,只是我想要的),但我能找到的只是它有隐式构造函数。这是默认的构造函数吗?如果是这样,怎么做

std::array<int, 3> a = {1,2,3}

工作?

可选奖励:为什么标准没有定义std::initializer_list的固定尺寸替代?像std::static_initializer_list<T, N>这样的东西。是否有计划在未来支持此类功能?它甚至需要吗?

1 个答案:

答案 0 :(得分:10)

您可以创建一个可变参数构造函数,并断言它提供了正确数量的参数:

template <size_t SZ>
struct Foo {
    template <typename... Args>
    Foo(Args... args) {
        static_assert(sizeof...(Args) <= SZ, "Invalid number of arguments");
        // ... stuff ...
    }
};

那样:

Foo<3> f;                // OK
Foo<3> f(1, 2, 3);       // OK
Foo<3> f(1, 2, 3, 4, 5); // error

作为初始化数组的示例,可能如下所示:

template <size_t SZ>
struct Foo {
    template <typename... Args>
    Foo(Args... args) 
    : v{{args...}}
    {
        static_assert(sizeof...(Args) <= SZ, "Invalid number of arguments");
    }

    std::array<int, SZ> v;
};

正如您所期望的那样正确构建v,但如果您尝试将超过SZ args传递给Foo的构造函数,那么您可以d在v之前看到有关初始化static_assert的错误。

为了更清楚static_assert错误,您可以将顶级Foo委托给私有构造函数,这些构造函数对于它们是否为有效构造函数需要额外的integral_constant参数:

template <typename... Args>
Foo(Args... args)
: Foo(std::integral_constant<bool, sizeof...(Args) <= SZ>{}, 
      args...)
{ }

private:
template <typename... Args>
Foo(std::true_type, Args... args)
: v{{args...}}
{ }

template <typename False, typename... Args>
Foo(False, Args... )
{ 
    // False is only ever std::false_type
    static_assert(False::value, "Invalid number of arguments!");
}