2016-05-20 8 views
17

Можно ли ограничить тип аргументов в конструкторе переменных?Как создать конструктор C++, который принимает переменное число int's

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

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?

ответ

15

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

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

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

Вы можете использовать std::integer_sequence<> пройти в Интс к 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...>; 

Тогда вы можете создать экземпляр класса class е так:

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

Вы уверены, что '' '' '' '' '' '' '' '' '' '' '' 'компилируют? – Barry

+0

@Barry - Да, они известны во время компиляции! –

+0

@StaffanGustafsson - Это было бы полезной информацией в вашем вопросе. –

-5

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

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

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

+0

Да, вы можете ограничить тип. И нет, вы не можете иметь расширение пакета в 'static_assert'. – Barry

14

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

} 
1

Вы обновили свой вопрос, чтобы указать, что все, что вам нужно, это время компиляции 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..." 
    } 
}; 

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

Смежные вопросы