2015-05-11 11 views
7

Ho il codice qui sotto, che mappa fondamentalmente una std::integer_sequence<> in un std::array<> in fase di compilazione:Perché passando oggetto constexpr da opere di riferimento const, ma dal valore non compilare

#include <iostream> 
#include <utility> 
#include <array> 

template<int...Is> 
constexpr auto make_array(const std::integer_sequence<int, Is...>& param) // this works */ 
// constexpr auto make_array(std::integer_sequence<int, Is...> param) // doesn't compile 
{ 
    return std::array<int, sizeof...(Is)> {Is...}; 
} 

int main() 
{ 
    constexpr std::integer_sequence<int, 1,2,3,4> iseq; 

    // If I pass by value, error: the value of 'iseq' is not usable in a constant expression 
    constexpr auto arr = make_array(iseq); 

    for(auto elem: arr) 
     std::cout << elem << " "; 
} 

Il codice funziona bene ogni volta make_array prende la sua argomentazione con il riferimento const. Ogni volta che provo di passarlo per valore, come nella linea commentato, sputa un errore:

error: the value of 'iseq' is not usable in a constant expression

constexpr auto arr = make_array(iseq); 

Perché è questo? Il parametro iseq è sicuramente un'espressione costante, perché non posso passarlo a make_array?

Ad esempio, il codice riportato di seguito funziona come previsto quando si passa per valore:

#include <iostream> 
#include <utility> 

struct Foo 
{ 
    int _m; 
    constexpr Foo(int m): _m(m){}; 
}; 

constexpr Foo factory_foo(int m) 
{ 
    return Foo{m}; 
} 

constexpr Foo copy_foo(Foo foo) 
{ 
    return foo; 
} 

int main() 
{ 
    constexpr Foo cxfoo = factory_foo(42); 
    constexpr Foo cpfoo = copy_foo(cxfoo); 
} 

EDIT

sto usando g ++ 5.1 da MacPorts. Utilizzando clang ++ 3.5, ottengo un messaggio di errore anche per il codice che compila con g ++ (con const di riferimento):

error: default initialization of an object of const type 'const std::integer_sequence' requires a user-provided default constructor

quindi credo che ci sia qualche problema con la mancanza di un costruttore di default fornita dall'utente, ma a questo punto non capisco davvero cosa sta succedendo.

+0

Quale compilatore e versione/i. –

+0

@ShafikYaghmour g ++ 5.1, proverò a clang presto. Vedi la modifica aggiornata, clang ++ sta sputando un errore anche nel caso di passaggio per riferimento 'const'. Probabilmente mi manca qualcosa sui medici di base in espressioni costanti. – vsoftco

risposta

5

Manca un inizializzatore su iseq. Si deve aggiungere che:

constexpr std::integer_sequence<int, 1,2,3,4> iseq{}; 
                ^^ 

Da [dcl.constexpr]:

A constexpr specifier used in an object declaration declares the object as const . Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.20). Otherwise, or if a constexpr specifier is used in a reference declaration, every fullexpression that appears in its initializer shall be a constant expression. [ Note: Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization is part of such a full-expression. —end note ]
[ Example:

struct pixel { 
    int x, y; 
}; 
constexpr pixel ur = { 1294, 1024 }; // OK 
constexpr pixel origin;    // error: initializer missing 

—end example ]

Inoltre, come suggerisce Columbo nella sua comment e answer, semplicemente essere inizializzato è insufficent. È necessario anche un costruttore fornite dall'utente, come per [dcl.init]:

If a program calls for the default initialization of an object of a const-qualified type T , T shall be a class type with a user-provided default constructor.

È un po 'strano avere la sezione più pertinente (dcl.constexpr) presentano una descrizione incompleta dei requisiti per un oggetto constepxr dichiarazione.

+0

Darn !!!! E 'stata una soluzione semplice :) Quindi immagino che g ++ abbia un bug. Non mi è nemmeno passato per la mente di controllare solo la definizione di 'iseq', per la quale clang ++ avrebbe sputato un errore. – vsoftco

+0

Ho visto quella citazione quando ho controllato la cosa implicita const, +1 – Columbo

+0

@Columbo segnalerà il bug per g ++ (se non è già stato segnalato) – vsoftco

6

If a program calls for the default initialization of an object of a const-qualified type T , T shall be a class type with a user-provided default constructor.

Tuttavia, integer_sequence non ha nessuna costruttori forniti dall'utente, e constexpr implica const per le variabili, quindi non si può definire un oggetto di quel tipo constexpr senza un inizializzatore.
Aggiunta di un inizializzatore makes it compile on Clang.

+0

Grazie, ho imparato qualcosa oggi! – vsoftco

Problemi correlati