С++. Перегрузка конструкторов с variadic template

template<typename ...Ts>
class Test
{
    private:
        std::tuple<Ts...> _tpl;

    public:
        Test() : _tpl{ std::tuple{Ts{}... } } {}  //ctor1
        Test(Ts... ob) : _tpl { std::tuple{ob... } } {} // ctor2
};
int main()
{
    Test<int, float> a; // ctor1 ok
    Test b{10, 2.5};    // ctor2 ok
    //Test<> c{};  // compile error
    return 0;
}

Как сделать так, чтобы можно было создавать объект класса Test с нулевым числом параметров? При этом оба существующих конструктора нужно оставить.


Ответы (2 шт):

Автор решения: HolyBlackCat

Вот так:

Test() : _tpl{ std::tuple{Ts{}... } } {}  //ctor1
Test(Ts... ob) requires(sizeof...(Ts) > 0) : _tpl { std::tuple{ob... } } {} // ctor2

Но лучше вот так:

Test() {}
Test(Ts... ob) requires(sizeof...(Ts) > 0) : _tpl(std::move(ob)...) {}

И передачу по универсальной ссылке тоже.

Выбирайте. Раз:

template <typename ...P>
class Test
{
  private:
    std::tuple<P...> _tpl;

  public:
    template <typename ...Q>
    Test(Q &&... params) : _tpl(std::forward<Q>(params)...) {}
};
template <typename ...P> Test(P &&...) -> Test<std::decay_t<P>...>;

Два:

template <typename ...P>
class Test
{
  private:
    std::tuple<std::decay_t<P>...> _tpl;

  public:
    Test() {}
    Test(P &&... params) : _tpl(std::forward<P>(params)...) {}
};
template <typename ...P> Test(P &&...) -> Test<P...>;
→ Ссылка
Автор решения: Алексей Ларин

Решение. Дополнительно, учитывает передачу параметров как lvalue. Спасибо HolyBlackCat! 15 минут назад

template<typename ...Ts>
class Test
{
    private:
        std::tuple<Ts...> _tpl;

    public:

        Test() {}
        Test(Ts &&...ob) requires(sizeof...(Ts) > 0) : _tpl(std::move(ob)...) {}
        Test(Ts &...ob) requires(sizeof...(Ts) > 0) : _tpl(std::forward<Ts>(ob)...) {}
};
int main()
{
    Test<int, float> a; // ctor1 ok
    Test b{10, 2.5};    // ctor2 ok
    Test c; // ctor1
    int i;
    float f;
    Test d{i, f};    // ctor3 ok
    return 0;
}
→ Ссылка