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

Как я могу создать конструктор С++, который принимает переменное число 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?

4b9b3361

Ответ 1

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

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>{} );
}

Ответ 2

Вы можете использовать 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!

}

Ответ 3

Вы обновили свой вопрос, указав, что все, что вам нужно, это время 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. Если ваш компилятор не поддерживает сгиб-выражения, просто замените их на ручную all_of.

Ответ 4

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

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

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