2013-02-14 71 views
8

是否可以为constexpr变量分配一个唯一地址,即对于变量可用的所有翻译单元(通常是通过标头)是否都是相同的?考虑下面的例子: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; 
} 

编译a.ccb.cc和分开,并使用gcc 4.7连接在一起,我看到印刷两个不同的地址。如果我在标题中添加了关键字extern,我得到了一个链接器错误duplicate symbol _foo in: a.o and b.o,我觉得有点令人惊讶,因为我认为添加extern会更有可能导致编译器从另一个对象导入该符号,而不是从当前对象中导出该符号。但似乎我对事物如何运作的理解在这里是错误的。

是否有合理的方法在一个头文件中声明constexpr,以便所有的翻译单元都可以在其常量表达式中使用它,并且所有翻译单元都同意该符号的地址?我希望一些额外的代码来表示这个符号实际上属于的单个翻译单元,就像extern和非extern变量没有constexpr一样。

+3

我相信你'foo'具有内在联系,所以你看到两个单独的副本。解决问题的常用方法是在头文件中声明'extern const int foo',并在* one *翻译单元中将其实现为'const int foo = 42;'。但是它可能显然不是一个常量表达式,因为'int a [foo]'需要在编译时解析,而不仅仅是在链接时。 – 2013-02-14 10:13:29

+2

也许还有另一种方法来实现你想要做的事情。那么......你想用这个地址做什么? – 2013-02-14 10:49:09

+0

@NicolBolas:到目前为止,我一直试图去处理'constexpr'。我习惯于对'const'全局变量使用外部链接,以避免重复的内存分配,即使有人决定采用这种野兽的地址。现在用'constexpr'这个似乎不再可能了。所以我实际上试图找出的是,即使我现在无法想象的一些奇怪的代码决定将这些东西的地址都放在这个地方,是否有办法避免数据重复。 – MvG 2013-02-14 11:06:03

回答

11

如果您需要获取constexpr变量的地址,请将其声明为静态成员变量。它可以用这种方式作为常量表达式(与使用返回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; 
} 

输出:

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

我认为constexpr更多的是函数的返回值是不变的。您可以将一个常量变量绑定到constexpr函数的返回值,并将其暴露给外部。例如:

// 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(); 
} 

我的结果是:

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

但是,通常应足以使foo_expr函数本身外部可见的,与呼叫者将使用foo_expr()获得价值而不是把它的像一个变量。