Подтвердить что ты не робот

Как параметризовать количество параметров конструктора?

Я хочу принять до нескольких параметров (этот номер определяется в параметре шаблона) в конструкторе класса шаблона. Я не могу использовать 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.

Я бы подумал, что может быть какая-то магия шаблона (variadic templates?), но я не могу даже определить правильный синтаксис для использования в конструкторе. Я не могу вызывать конструктор рекурсивно... могу ли я?

Я попытался найти определение конструктора для std::array (поскольку он не позволяет больше параметров, чем размер массива, именно то, что я хочу), но все, что я мог найти, это то, что у него есть неявные конструкторы, Это конструкторы по умолчанию? Если да, то как

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

работа?

Дополнительный бонус: почему стандарт не определил альтернативу с фиксированным размером std::initializer_list? Что-то вроде std::static_initializer_list<T, N>. Существуют ли какие-либо планы по поддержке такого рода функций в будущем? Это даже необходимо?

4b9b3361

Ответ 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!");
}