Как я могу создать конструктор C++, который принимает переменное число int


Это возможно, чтобы ограничить тип аргументов в конструктор с переменным числом аргументов?

Я хочу иметь возможность выразить

X x1(1,3,4);
X x2(3,4,5);

// syntax error: identifier 'Args'
class X {
template<int ... Args> X(Args...)
{
}
};
// this works but allows other types than int
class Y {
template<typename ... Args> Y(Args...)
{
}
};

Изменить, чтобы прояснить намерение:

Чего я хочу добиться, так это сохранить данные, переданные в конструктор (константы, известные во время компиляции), в статический массив.

Так что есть и другие

template<int ...values>
struct Z
{
    static int data[sizeof...(values)];
};

template<int ... values>
int Z<values...>::data[sizeof...(values)] = {values...};

И в конструкторе X я хотел бы использовать Z так:

class X {
    template<int ... Args> X(Args...)
    {
        Z<Args...>::data // do stuff with data
    }
};

Возможно ли это, что я должен использовать integer_sequence?

4 17

4 ответа:

Так как у вас есть следующее:

template<int... values>
struct Z
{
    static int data[ sizeof...( values ) ];
};

template <int... values>
int Z<values...>::data[ sizeof...( values ) ] = { values... };

Вы можете использовать std::integer_sequence<>, чтобы передать ints в Z<>:

struct X
{
    template <int... values>
    X( std::integer_sequence<int, values...> )
    {
        for ( int i{ 0 }; i < sizeof...( values ); ++i )
            Z<values...>::data[ i ]; // do stuff with data
    }
};

Вы можете сделать себе вспомогательный тип, чтобы облегчить вызов ctor:

template <int... values>
using int_sequence = std::integer_sequence<int, values...>;

Тогда вы можете создать экземпляр своего класса следующим образом:

int main()
{
    X x( int_sequence<1, 3, 5>{} );
}

Вы можете использовать std::initializer_list:

#include <iostream>
#include <initializer_list>

void myFunc(std::initializer_list<int> args)
{
    for (int i: args) std::cout << i << '\n';
}
int main(){

    myFunc({2,3,2});
    // myFunc({2,"aaa",2}); error!

}

Вы обновили свой вопрос, чтобы указать, что все, что вам нужно,-это время компиляции std::integer_sequence, что замечательно.

Но просто ради будущих читателей, которые могут прийти сюда в поисках ответа, я хотел бы также ответить на ваш первоначальный вопрос "возможно ли ограничить тип аргументов в вариадическом конструкторе?"

Да. Один путь (лучший путь? Я не уверен) является SFINAE на дополнительный параметр шаблона, как это:

struct X {
    template<
        class... TT,
        class E = std::enable_if_t<(std::is_same_v<TT, int> && ...)>
    >
    X(TT... tt) {
        // do stuff with the ints "tt..."
    }
};

&& ... является складчатым выражением, новым в С++17. Если ваш компилятор не поддерживает fold-выражения, просто замените его на свернутый вручную all_of.

Нет, вы не можете ограничить тип. Однако вы можете использовать static_assert. Было бы что-то вроде этого:

static_assert(std::is_same<int, Args>::value ..., "have to be ints.");

Не пытались использовать расширение в static_assert, как это. Вам может понадобиться constexpr, который возвращает bool или что-то еще.