Ответ 1
Вы можете создать вариационный конструктор и просто утверждать, что ему было предоставлено правильное количество аргументов:
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
, вы увидите ошибку при инициализации 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!");
}