2013-06-17 11 views
5

Se abbiamo un file di intestazione widget.hpp con i contenuti di seguito:constexpr e ODR

constexpr int foo = 10; 

struct widget 
{ 
    int bars[foo]; 
}; 

... e abbiamo due unità di traduzione generati da due file di origine cui entrambi includono solo widget.hpp, fa questo violare quella regola di definizione (in particolare, l'uso di foo viola la regola di una definizione)?

foo ha un collegamento interno ma è anche un'espressione costante. Dalla mia lettura del 3.2.6 nello standard C++ 11, che citerò di seguito, questo è ben formato se il requisito # 2 non si riferisce solo ai membri dei dati statici.


3.2.6 requisito # 2:

in ogni definizione di D, nomi corrispondenti, guardato secondo 3.4, si riferiscono a un'entità definita nella definizione di D o adotta fare riferimento alla stessa entità, dopo la risoluzione di sovraccarico (13.3) e dopo l'abbinamento della specializzazione modello parziale (14.8.3), eccetto che un nome può fare riferimento a un oggetto const non volatile con interno o nessun collegamento se l'oggetto ha lo stesso tipo letterale in tutte le definizioni di D, e l'oggetto viene inizializzato con un'espressione costante (5.19), e l'oggetto non è ODR utilizzato, e l'oggetto ha lo stesso valore in tutte le definizioni di D

risposta

3

L'unico posto dove posso vedere alcun spazio per la domanda circa il vostro caso sarebbe indica se il tuo uso di foo corrisponde o meno a odr-used oppure no. Forse il modo più semplice per chiarire almeno l'intento sarebbe quello di citare la sezione corrispondente di n1337 (immediatamente seguito lo standard ufficiale, per lo più pulizia qualche fraseggio, come in questo caso):

[...] un nome può riferirsi a un oggetto const con collegamento interno o nessun collegamento se l'oggetto ha lo stesso tipo letterale in tutte le definizioni di D e l'oggetto viene inizializzato con un'espressione costante (5.19) e il valore (ma non l'indirizzo) di l'oggetto è usato e l'oggetto ha lo stesso valore in tutte le definizioni di D;

L'utilizzo soddisfa chiaramente tutti questi requisiti.

  1. foo ha tipo int in ogni caso.
  2. foo viene inizializzato con un'espressione costante.
  3. si utilizza solo il valore, non l'indirizzo, di foo.
  4. foo ha lo stesso valore in tutte le definizioni di widget.

Detto questo, si sarebbe probabilmente meglio a cambiare foos ad un std::vector invece:

struct widget { 
    std::vector<int> bars; 

    widget : bars(foo) {} 
}; 
0

I don' t ottieni la tua interpretazione Il testo citato si applica correttamente all'esempio quotato. Finché lo includi in tutte le TU. Violare ODR è necessario rompere qualcosa del testo:

constexpr double foo = 10; // type 
constexpr int foo = ret_10(); // non-const init 
constexpr int foo = 42; // value 

E per rompere ODR-uso penso che si deve prendere il suo indirizzo.

1

Quanto alle definizioni multiple di foo, non ritengo foo è ODR utilizzato perché soddisfa i requisiti per apparire in un'espressione costante, secondo 3.2.3:

A x variabile il cui nome compare come espressione ex potenzialmente valutati è ODR-utilizzati se x è un oggetto che soddisfa i requisiti per apparire in un'espressione costante

Pertanto quanto non è ODR utilizzato ODR-regola non si applica ai it, 3.2.4:

Ogni programma deve contenere esattamente un definizione di ogni funzione non in linea oppure variabile che è ODR utilizzato in quel programma

Quanto alle due diverse definizioni di widget, e se sono sufficientemente simili in base al punto 3.2.6. La risposta è sì perché N3485 3.2.6:

un nome può fare riferimento a un oggetto const [sì, constexpr è const] con interno [constexpr è interno] o nessun legame se l'oggetto ha lo stesso tipo letterale [sì, sia int] in tutte le definizioni di D, e l'oggetto è inizializzato con un'espressione costante [sì, 10], e viene utilizzato il valore (ma non l'indirizzo) dell'oggetto e l'oggetto ha lo stesso valore [sì, 10] in tutte le definizioni di D

Quindi, anche se il nome foo si riferisce a due diverse entità nelle due diverse TU, queste due entità soddisfano i requisiti specificati.

(In pratica funziona perché il compilatore layout di due classi in modo identico, quindi il codice generato dai due TU sarà compatibile.)