2013-04-07 18 views
8

Nel rispondere this question, ho provato il seguente codice con GCC (code compiled) e clang (code rejected):constexpr statica puntatore a funzione, differenza tra i compilatori

typedef long (*func)(int); 

long function(int) { return 42; } 

struct Test 
{ 
    static constexpr func f = &function; 
}; 

template<func c> 
struct Call 
{ 
    static void f() 
    { 
     c(0); 
    } 
}; 

int main() 
{ 
    Call<Test::f>::f(); 
} 

io non sono sicuro che il compilatore è giusto, anche se penso che l'inizializzazione di constexpr di Test::f sia ok. Le uscite errore clang è:

error: non-type template argument for template parameter of pointer type 'func' 
     (aka 'long (*)(int)') must have its address taken 
  1. quale compilatore è giusto?
  2. Se clang ha ragione, perché e cosa significa veramente questo errore?

EDIT: per il "perché", vedi DyP's question.

+0

Mi chiedo anche se non 'e function' è in realtà un inizializzatore valido per' constexpr'. Entrambi i compilatori sembrano pensarla così. Ma sembra incerto per me. Questo non è noto al momento della compilazione, solo al momento del collegamento. – Omnifarious

+0

'& function' è l'indirizzo di una funzione, quindi per me è noto al momento della compilazione ... Ad esempio, puoi passare un puntatore a funzionare come argomento modello. – Synxis

+1

Un puntatore a una funzione è una cosa ... se questo faceva parte di una libreria condivisa, ad esempio, in che modo l'indirizzo può essere qualificato come 'constexpr'? –

risposta

8

14.3.2 Template non argomenti di tipo [temp.arg.nontype]

Un modello-argomento per un non-tipo, non-template-parametro deve essere uno dei seguenti:

[...]

- un'espressione costante (5.19) che indica l'indirizzo di un oggetto con una memoria statica> durata e collegamento esterno o interno o una funzione con linkage esterno o interno, inclusi i modelli di funzione e modello di funzione -ids ma escl uding membri della classe non statici, espressi (ignorando parentesi) come & id-espressione, eccetto che il & può essere omesso se il nome si riferisce a una funzione o array e deve essere omesso se il corrispondente parametro-parametro è un riferimento; [...]

(n3485, sottolineatura mia)

Non so esattamente il motivo per cui è stato limitato, ma penso che potrebbe essere legato al fatto che l'indirizzo funzione non è disponibile a compilare il tempo (potrebbe esserci un sostituto per scopi di istanziazione del modello).


Edit: Enhanced risposta a causa di una domanda di follow-up (commento) di Synxis

constexpr func = &function; 

^questo è ben formato; è possibile utilizzare l'indirizzo di una funzione per inizializzare un oggetto constexpr. Il problema è che è esplicitamente vietato l'uso di puntatori come non-argomenti di tipo modello diverso della forma &identifier:

using My_Call  = Call < &function >; // fine 

constexpr func mypointer = &function; // fine 
using My_Ind_Call = Call <func>;  // forbidden, argument not of form `&id` 
+3

Sembra una svista. Se assegni un 'constexpr' ad un' constexpr' e poi lo assegni ad un altro 'constexpr', dovrebbe essere transitivo. – Omnifarious

+3

@Omnifarious It ** è ** un 'constexpr'. Ma è esplicitamente vietato come argomento modello non di tipo. – dyp

+0

Beh, è ​​interessante. Esplicitamente non trattato ortogonalmente Mi chiedo quale sia il ragionamento. Tuttavia, ho un forte sospetto. La mia ipotesi è che gli oggetti che possono essere trasferiti dal linker sono indicati per nome nelle regole di mangling per i modelli. Richiedere ai compilatori di portare in giro il nome originale per "constexpr" cose del genere è piuttosto oneroso e probabilmente impossibile in alcuni scenari. – Omnifarious

Problemi correlati