非积分常数

def*_*ode 16 c++ inline constants c++11

我想要一个带有非整数常量的头文件,例如一个类.注意常数也并不需要是一个编译时间常数.

static const std::string Ten = "10";
Run Code Online (Sandbox Code Playgroud)

这编译但不可取,因为每个编译单元现在都有自己的Ten副本.

const std::string Ten = "10";
Run Code Online (Sandbox Code Playgroud)

这将编译但会因为多重定义的Ten的链接器错误而失败.

constexpr std::string Ten = "10"s;
Run Code Online (Sandbox Code Playgroud)

这可以工作,但前提是字符串构造函数也是constexpr.它会但是我不能指望每个非整数常量都有一个constexpr构造函数......或者我可以吗?

extern const std::string Ten = "10";
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但我担心如果我错误地呼吸,我会收到链接器错误.

inline const std::string Ten( ) { return "10"; }
Run Code Online (Sandbox Code Playgroud)

这有我想要的一切,除了干净的语法.另外,现在我必须将常量称为函数调用Ten().

inline const std::string = "10";
Run Code Online (Sandbox Code Playgroud)

这似乎是理想的解决方案.当然inline,标准不允许变量.

  • c ++标准中是否有一些内容表明外部版本应该有用,或者我很幸运它与GCC一起使用?
  • 是否有令人信服的理由不允许内联变量?
  • c ++ 03有更好的方法还是c ++ 0x会有更好的方法?

AnT*_*AnT 27

你好像混淆了他们.

你是对的

static const std::string Ten = "10"; 
Run Code Online (Sandbox Code Playgroud)

版.它将"工作",但它将在每个翻译单元中创建一个单独的对象.

没有版本static将具有相同的效果.它不会产生链接器错误,但会在每个转换单元中定义一个单独的对象.在C++中,语言const对象默认具有内部链接,这意味着

const std::string Ten = "10"; // `static` is optional
Run Code Online (Sandbox Code Playgroud)

与之前的版本完全相同static.

extern和初始化程序的版本

extern const std::string Ten = "10"; // it's a definition!
Run Code Online (Sandbox Code Playgroud)

会产生一个定义具有外部链接一个对象的(它是一个定义,因为一个初始化的存在).版本将导致链接器错误,因为您将最终得到具有外部链接的对象的多个定义 - 违反ODR.

这是你如何做到的:

为了实现您想要实现的目标,您必须在头文件中声明您的常量

extern const std::string Ten; // non-defining declaration
Run Code Online (Sandbox Code Playgroud)

然后在一个且只有一个实现文件中定义它(使用初始化程序)

extern const std::string Ten = "10"; // definition, `extern` optional
Run Code Online (Sandbox Code Playgroud)

(如果常量被预先声明为extern,那么extern在定义中是可选的.即使没有显式,extern它也会定义一个带有外部链接的const对象.)

  • @Gman:没有`extern`,它会定义一个带有*internal*链接的`const`对象.但是,之前的`extern`声明的存在超越了这一点.所以定义中的`extern`是可选的.我把它放在那里"以防万一".有些人可能认为它稍微提高了可读性,因为它明确表明它正在定义一个带有*external*链接的`const`对象.如果没有"外部",那么不知道之前声明的人可能会认为联系是内部的.但同样,在这种情况下它是可选的(因为之前的声明). (5认同)
  • 啊,我知道,这是有道理的. (2认同)

pax*_*blo 10

我不知道C++中是否有更好的方法,但C中最好的方法(也适用于C++)是你列出的方法之一.

有一个单独的编译单元(例如ten.cpp),只保存数据:

const std::string Ten = "10";
Run Code Online (Sandbox Code Playgroud)

和一个头文件(例如ten.h)声明它,以便它可以在别处使用:

extern const std::string Ten;
Run Code Online (Sandbox Code Playgroud)

然后你必须确保任何想要使用它的编译单元包括头文件(例如ten.h),并且任何想要使用它的可执行文件链接到单独的编译单元(例如ten.o).

这为您提供了变量的一个副本,可在任何地方访问.当然,您可以在头文件中将其定义为静态,并为每个编译单元创建一个副本.这将简化您需要的文件,静态将确保没有双重定义的符号.但这不是我推荐过的.

我不知道你为什么说:

但是,如果我错误地呼吸,我恐怕会收到链接器错误

这是很久以前的公认实践,如果你想称自己为C++程序员(没有任何侮辱),你应该知道所有这些东西是如何组合在一起的.


Chr*_*utz 6

extern版本是接近你想要什么.这里:

// in the file tenconstant.cpp
const std::string Ten = "10";

// in the file tenconstant.h
extern const std::string Ten;

// in your file
#include "tenconstant.h"

// do stuff with Ten
Run Code Online (Sandbox Code Playgroud)

你需要为链接器定义一次,这是目的myconstants.cpp,但是在你使用它的任何地方声明,这是目的myconstants.h.对于一个变量来说,这看起来有点笨拙,但是对于一个更大的项目,你可能会有一个很好的标题,你可以使用它很多.