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