2016-05-17 29 views
7

In this presentation intorno alle 00:19:00, Andrei Alexandrescu spiega l'implementazione della sua macro SCOPE_EXIT. Egli crea un oggetto ScopeGuard sullo stack che esegue una lambda sulla distruzione:Come può __COUNTER__ causare una violazione ODR qui?

#define ANONYMOUS_VARIABLE(str) \ 
    CONCATENATE(str, __COUNTER__) 

namespace detail { 
    enum class ScopeGuardOnExit {}; 
    template <typename Fun> 
    ScopeGuard<Fun> 
    operator+(ScopeGuardOnExit, Fun&& fn) { 
     return ScopeGuard<Fun>(std::forward<Fun>(fn)); 
    } 
} 

#define SCOPE_EXIT \ 
    auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \ 
    = ::detail::ScopeGuardOnExit() + [&]() 

Finora, così ben noto (si afferma anche nei suoi diapositive che si tratta di un vecchio cappello). L'utilizzo è simile al seguente:

void foo() 
{ 
    SCOPE_EXIT{ printf("foo exits"); }; 
} 

Ma a 01:04:00, Chandler Carruth sostiene che questo uso del __COUNTER__ macro per creare un nome di "anonimo" causerebbe una violazione di ODR quando viene utilizzato in una funzione inline. Può essere vero? La macro viene utilizzata solo per creare un nome di variabile locale, non un nome di tipo o qualcosa del genere, quindi come ciò potrebbe causare una violazione ODR?

risposta

8

Supponiamo che la funzione inline si trovi in ​​un'intestazione inclusa in due diverse unità di traduzione e che il valore del contatore si trovi su un valore diverso in ciascuna.

Quindi esistono due definizioni della funzione inline con nomi diversi per la variabile. Questa è una violazione ODR: devi utilizzare la stessa sequenza di token per ogni definizione.

(Anche se in pratica sarei molto sorpreso se ha causato alcun problema.)

+0

ho appena venuto alla stessa conclusione, mi ha portato un po 'per capire che si tratta di circa la definizione della funzione stessa. Ma questo ha senso, anche se si tratta solo di un nome variabile diverso. Immagino che si possa solo sperare che questo non causi problemi ... forse la macro LINEA sarebbe una scelta migliore qui? – Horstling

+0

Sì, a meno che non si desideri dichiarare più di una di queste cose su un'unica riga. (Oppure stai scherzando con '# line'.) –

Problemi correlati