繁体   English   中英

非积分常数

[英]non-integral constants

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

static const std::string Ten = "10";

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

const std::string Ten = "10";

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

constexpr std::string Ten = "10"s;

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

extern const std::string Ten = "10";

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

inline const std::string Ten( ) { return "10"; }

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

inline const std::string = "10";

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

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

你好像混淆了他们。

你是对的

static const std::string Ten = "10"; 

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

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

const std::string Ten = "10"; // `static` is optional

static的先前版本完全等效。

带有extern和初始化程序的版本

extern const std::string Ten = "10"; // it's a definition!

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

这是你如何做到的:

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

extern const std::string Ten; // non-defining declaration

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

extern const std::string Ten = "10"; // definition, `extern` optional

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

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

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

const std::string Ten = "10";

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

extern const std::string Ten;

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

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

我不知道你为什么说:

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

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

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

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

以这种方式创建静态用户定义类型是一个坏主意。 当您有多个此类UDT时,无法控制实例化的顺序。 这在小型项目中不是问题,但并非所有项目都很小。 最好的做法是将静态数据作为所有普通的旧数据类型 - 原始指针 - 并以适当的方式初始化它们,以指向程序启动时所需的实例,或者何时需要它们。 这让你掌控一切。

您的问题表明这些类型不需要是编译时常量。 如果是这样,并且您有一个多线程程序,则您的对象需要保护其状态不受多个线程的同时访问。 如果某些对象不是线程安全的,那么除了对象本身之外,还需要一个互斥对象来保护其状态,并且必须具有相同的链接,并且需要初始化。 所有这些使得程序的全局状态变得复杂,这可能是一种不可接受的方式。

我认为这里的其他答案更好,但如果您使用标题完成所有操作,您可以使用简单的包装函数有效地inline您的对象(正如您特别要求的那样)。

inline const std::string &get_ten() {
    static const std::string ten = "10";
    return ten;
}

将只有一个string ,初始化一次,并且您不需要头文件之外的任何内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM