2016-05-20 13 views
17

È possibile limitare il tipo di argomenti in un costruttore variadic?Come posso creare un costruttore C++ che accetta un numero variabile di int

Voglio essere in grado di esprimere

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

modifica per chiarire l'intento:

Quello che voglio raggiungere è quello di memorizzare i dati passati in un costruttore (costanti noti al momento della compilazione) in una matrice statica.

quindi ci sono alcune altre

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

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

e nel costruttore di X vorrei usare Z come questo:

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

Che è possibile, il nostro Devo usare integer_sequence?

risposta

15

Dal momento che avete il seguente:

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

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

È possibile utilizzare std::integer_sequence<> a passare nei interi per 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 
    } 
}; 

potete fare voi stessi un tipo di aiuto per rendere più facile per chiamare il Ctor:

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

Quindi è possibile creare un'istanza della classe lik e così:

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

Sei sicuro che le 'int's di OP sono costanti di tempo di compilazione? – Barry

+0

@Barry - Sì, sono noti al momento della compilazione! –

+0

@StaffanGustafsson - Sarebbero state utili informazioni nella tua domanda. –

-5

No, non è possibile vincolare il tipo. È comunque possibile utilizzare static_assert. Sarebbe qualcosa di simile:

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

Non ho provato ad utilizzare un'espansione in un static_assert del genere però. Potrebbe essere necessario un constexpr che restituisce bool o qualcosa del genere.

+0

Sì, è possibile vincolare il tipo. E no, non puoi avere espansione del pacchetto in un 'static_assert' come quello. – Barry

14

È possibile utilizzare 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

aver aggiornato la tua domanda per indicare che tutto ciò che serve è un momento della compilazione std::integer_sequence, che è grande.

Ma solo per i futuri lettori che potrebbero venire qui a cercare la risposta, vorrei anche rispondere alla tua domanda iniziale "È possibile limitare il tipo di argomenti in un costruttore variadico?"

Sì. Un modo (? Il modo migliore che non sono sicuro) è di SFINAE su un parametro di modello supplementare, in questo modo:

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..." 
    } 
}; 

Il && ... è un fold-espressione, di nuovo in C++ 17. Se il tuo compilatore non supporta le espressioni di piegatura, sostituiscilo con una mano arrotolata all_of.

Problemi correlati