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


我想在模板类构造函数中接受多个参数(此数字在模板参数中定义)。我不能用 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>。是否有计划在未来支持此类功能?它甚至需要吗?


7769
2018-06-18 20:48


起源

为了澄清,你打算写 std::array<int, s>, 对?我找不到了 n 你有任何地方。也 std::array 利用 聚合初始化 - Raphael Addile
你在我编辑修复它的那一刻得到了我:)感谢您的链接! - Cássio Renan
如何使用矢量? - liran63
你到底想要什么?你想把尺寸作为第一个参数吗?或者您是否希望自动为您处理?如果你这样做,请使用 std::vector 我认为它的大小功能。 - VermillionAzure
当参数少于限制时,您打算做什么?我想知道具有默认参数的单个构造函数是否足够。 - Jon Chesterfield


答案:


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

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 to Foo的构造函数,你会看到初始化时的错误 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!");
}

10
2018-06-18 20:59



你怎么会“获得”参数呢? - vsoftco
我读了OP的声明“... 取决于 一些参数......“这意味着OP希望接受一个 变量 参数数量但不超过最大数量。在那种情况下,我认为 static_assert 必须使用 <= 代替 ==。 - Remy Lebeau
@RemyLebeau哦,好点。纠正。 - Barry
@vsoftco我以为你没有得到它们?你刚才 (Args...) 如果你有正确的构造函数在等待,那么当你替换时,事情应该是好的,对吧? - VermillionAzure
@vsoftco让它成为一个 std::array<int, SZ> v 相反,然后只是 v({{args...}}) 工作得很好。 - Barry