2013-02-14 26 views
8

È possibile assegnare un indirizzo univoco per una variabile constexpr, vale a dire lo stesso per tutte le unità di traduzione in cui la variabile è disponibile (di solito attraverso un'intestazione)? Si consideri il seguente esempio:Indirizzo univoco per variabile constexpr

// foo.hh 
#include <iostream> 
constexpr int foo = 42; 

// a.cc 
#include "foo.hh" 
void a(void) { std::cout << "a: " << &foo << std::endl; } 

// b.cc 
#include "foo.hh" 
extern void a(void); 
int main(int argc, char** argv) { 
    a(); 
    std::cout << "b: " << &foo << std::endl; 
} 

Compilazione a.cc e b.cc separatamente, e collegandoli tra loro con gcc 4.7, vedo due indirizzi diversi stampati. Se aggiungo la parola chiave extern nell'intestazione, ottengo un errore del linker duplicate symbol _foo in: a.o and b.o che trovo un po 'sorprendente, perché pensavo che l'aggiunta di extern avrebbe più probabilmente indotto il compilatore a importare quel simbolo da un altro oggetto invece di esportarlo dall'oggetto corrente . Ma sembra che la mia comprensione di come funzionano le cose qui è sbagliata.

Esiste un modo ragionevole per dichiarare un constexpr in un'intestazione, in modo che tutte le unità di traduzione possano utilizzarlo nelle loro espressioni costanti e in modo tale che tutte le unità di traduzione concordino sull'indirizzo di tale simbolo? Mi aspetto un codice aggiuntivo per indicare la singola unità di traduzione a cui questo simbolo appartiene, esattamente come con le variabili extern e non extern senza constexpr.

+3

Credo che il tuo 'foo' abbia un collegamento interno, quindi stai vedendo due copie separate. La solita soluzione per il tuo problema è avere un 'extern const int foo' dichiarato nell'intestazione e implementato come' const int foo = 42; 'in * one * translation unit. Ma spesso non può essere un'espressione costante, dal momento che 'int a [foo]' deve essere risolvibile al momento della compilazione, e non solo al momento del collegamento. –

+2

Forse c'è un altro modo per ottenere ciò che stai cercando di fare. Quindi ... cosa * esattamente * stai cercando di fare con questo indirizzo? –

+0

@NicolBolas: Finora sto cercando di fare i conti con 'constexpr' in generale.Avevo l'abitudine di usare il collegamento esterno per le variabili globali di 'const' per evitare l'allocazione di memoria duplicata anche se qualcuno decidesse di prendere un indirizzo di tale bestia. Ora con 'constexpr' questo non sembra più possibile. Quindi quello che sto cercando di scoprire è se c'è un modo per evitare la duplicazione dei dati anche se qualche codice strano che non riesco a immaginare in questo momento decide di prendere indirizzi di queste cose dappertutto. – MvG

risposta

11

Se è necessario prendere l'indirizzo della variabile constexpr, dichiararlo come variabile membro statica. Può essere usato come espressione costante in questo modo (al contrario di usare una funzione che restituisce un const).

foo.hpp:

#ifndef FOO_HPP 
#define FOO_HPP 

struct Foo { 
    static constexpr int foo { 42 }; // declaration 
}; 

#endif // FOO_HPP 

foo.cpp:

#include "foo.hpp" 

constexpr int Foo::foo; // definition 

bar.cpp:

#include "foo.hpp" 

const int* foo_addr() { 
    return &Foo::foo; 
} 

int foo_val() { 
    return Foo::foo; 
} 

main.cpp:

#include <iostream> 
#include "foo.hpp" 

extern const int* foo_addr(); 
extern int foo_val(); 

constexpr int arr[Foo::foo] {}; // foo used as constant expression 

int main() { 
    std::cout << foo_addr() << " = " << foo_val() << std::endl; 
    std::cout << &Foo::foo << " = " << Foo::foo << std::endl; 
} 

Uscita:

$ g++ -std=c++11 foo.cpp bar.cpp main.cpp -o test && ./test 
0x400a44 = 42 
0x400a44 = 42 
1

Penso che constexpr si intende più per le funzioni il cui valore di ritorno è costante. È possibile associare una variabile costante al valore restituito di una funzione constexpr e esporla invece esternamente. Ad esempio:

// constexpr.h 
#ifndef __CONSTEXPR_H 
#define __CONSTEXPR_H 

extern const int foo; 

#endif // __CONSTEXPR_H 

// constexpr.cpp 
#include "constexpr.h" 

constexpr int foo_expr() 
{ 
    return 42; 
} 

const int foo = foo_expr(); 

// unit1.cpp 
#include <iostream> 
#include "constexpr.h" 

void unit1_print_foo() 
{ 
    std::cout << &foo << " = " << foo << std::endl; 
} 

// unit2.cpp 
#include <iostream> 
#include "constexpr.h" 

void unit2_print_foo() 
{ 
    std::cout << &foo << " = " << foo << std::endl; 
} 

// main.cpp 
extern void unit1_print_foo(); 
extern void unit2_print_foo(); 

int main(int, char**) 
{ 
    unit1_print_foo(); 
    unit2_print_foo(); 
} 

mio risultato è:

$ g++-4.7 -std=c++11 constexpr.cpp unit1.cpp unit2.cpp main.cpp -o test && ./test 
0x400ae4 = 42 
0x400ae4 = 42 

Tuttavia, dovrebbe normalmente essere sufficiente a rendere la funzione foo_expr stessa visibili esternamente, e chiamanti userebbe foo_expr() per ottenere il valore invece di trattarlo come una variabile.

Problemi correlati