[英]non-integral constants
I want a header file with a non-integral constant in it, eg a class. 我想要一个带有非整数常量的头文件,例如一个类。 Note the constant does not need to be a compile-time constant.
注意常数并不需要是一个编译时间常数。
static const std::string Ten = "10";
This compiles but is undesirable as each compilation unit now has its own copy of Ten. 这编译但不可取,因为每个编译单元现在都有自己的Ten副本。
const std::string Ten = "10";
This will compile but will fail with a linker error for multiply defined Ten. 这将编译但会因为多重定义的Ten的链接器错误而失败。
constexpr std::string Ten = "10"s;
This would work but only if the strings constructor was constexpr as well. 这可以工作,但前提是字符串构造函数也是constexpr。 It will be but I can't count on every non-integral constant to have a constexpr constructor ... or can I?
它会但是我不能指望每个非整数常量都有一个constexpr构造函数......或者我可以吗?
extern const std::string Ten = "10";
This seems to work but I'm afraid I'll get a linker error if I breath on it wrong. 这似乎有效,但我担心如果我错误地呼吸,我会收到链接器错误。
inline const std::string Ten( ) { return "10"; }
This has everything I want except a clean syntax. 这有我想要的一切,除了干净的语法。 Plus now I have to refer the constant as a function call,
Ten()
. 另外,现在我必须将常量称为函数调用
Ten()
。
inline const std::string = "10";
This seems to be the ideal solution. 这似乎是理想的解决方案。 Of course
inline
variables aren't allowed by the standard. 当然,标准不允许使用
inline
变量。
You seem to have them mixed up. 你好像混淆了他们。
You are right about 你是对的
static const std::string Ten = "10";
version. 版。 It will "work", but it will create a separate object in each translation unit.
它将“工作”,但它将在每个翻译单元中创建一个单独的对象。
The version without static
will have the same effect. 没有
static
的版本将具有相同的效果。 It won't produce linker errors, but will define a separate object in each translation unit. 它不会产生链接器错误,但会在每个转换单元中定义一个单独的对象。 In C++ language
const
objects have internal linkage by default, meaning that 在C ++语言中,
const
对象默认具有内部链接,这意味着
const std::string Ten = "10"; // `static` is optional
is exactly equivalent to the previous version with static
. 与
static
的先前版本完全等效。
The version with extern
and initializer 带有
extern
和初始化程序的版本
extern const std::string Ten = "10"; // it's a definition!
will produce a definition of an object with external linkage (it is a definition because of the presence of an initializer). 会产生与外部连接的对象的定义 (这是一个定义,因为一个初始化的存在)。 This version will result in linker errors, since you'll end up with multiple definitions of an object with external linkage - a violation of ODR.
此版本将导致链接器错误,因为您将最终得到具有外部链接的对象的多个定义 - 违反ODR。
In order to achieve what you are trying to achieve, you have to declare your constant in the header file 为了实现您想要实现的目标,您必须在头文件中声明您的常量
extern const std::string Ten; // non-defining declaration
and then define it (with initializer) in one and only one of the implementation files 然后在一个且只有一个实现文件中定义它(使用初始化程序)
extern const std::string Ten = "10"; // definition, `extern` optional
(If the constant is pre-declared as extern
, then extern
in the definition is optional. Even without an explicit extern
it will define a const object with external linkage.) (如果常量被预先声明为
extern
,那么定义中的extern
是可选的。即使没有显式的extern
它也会定义一个带有外部链接的const对象。)
I don't know if there's a better way in C++ but the best way in C (which will also work in C++) is one of the ones you've listed. 我不知道C ++中是否有更好的方法,但C中最好的方法(也适用于C ++)是你列出的方法之一。
Have a separate compilation unit (eg, ten.cpp
) holding just the data: 有一个单独的编译单元(例如,
ten.cpp
)只保存数据:
const std::string Ten = "10";
and a header file (eg, ten.h
) declaring it so it can be used elsewhere: 和一个头文件(例如,
ten.h
)声明它,以便它可以在别处使用:
extern const std::string Ten;
Then you just have to ensure any compilation unit that wants to use it include the header file (eg, ten.h
), and any executable that wants to use it link with the separate compilation unit (eg, ten.o
). 然后你必须确保任何想要使用它的编译单元包括头文件(例如,
ten.h
),并且任何想要使用它的可执行文件链接到单独的编译单元(例如, ten.o
)。
This gives you one copy of the variable, accessible anywhere. 这为您提供了变量的一个副本,可在任何地方访问。 Of course, you could just define it in the header file as static and have one copy per compilation unit.
当然,您可以在头文件中将其定义为静态,并为每个编译单元创建一个副本。 That would simplify what files you need to have and the static would ensure there's no doubly-defined symbols.
这将简化您需要的文件,静态将确保没有双重定义的符号。 But that's not something I'd ever recommend.
但这不是我推荐过的。
I don't know why you state: 我不知道你为什么说:
but I'm afraid I'll get a linker error if I breath on it wrong
但是,如果我错误地呼吸,我恐怕会收到链接器错误
This is accepted practice from long ago and you should know how all these things fit together if you wish to call yourself a C++ programmer (no insult intended). 这是很久以前的公认实践,如果你想称自己为C ++程序员(没有任何侮辱),你应该知道所有这些东西是如何组合在一起的。
The extern
version is close to what you want. extern
版本接近你想要的。 Here: 这里:
// 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
You need it to be defined once for the linker, which is the purpose of myconstants.cpp
, but declared everywhere you use it, which is the purpose of myconstants.h
. 你需要为链接器定义一次,这是
myconstants.cpp
的目的,但是在你使用它的任何地方声明,这是myconstants.h
的目的。 This may seem a bit unwieldy for one variable, but for a larger project, you will probably have a nice header that gets used a lot that you can stick this in. 对于一个变量来说,这看起来有点笨拙,但是对于一个更大的项目,你可能会有一个很好的标题,可以使用很多,你可以坚持这个。
It is a bad idea to create a static user-defined type in this way. 以这种方式创建静态用户定义类型是一个坏主意。 You can't control the order of instantiation when you have multiple such UDTs.
当您有多个此类UDT时,无法控制实例化的顺序。 This is not a problem in a small project, but not all projects are small.
这在小型项目中不是问题,但并非所有项目都很小。 It's a better idea to make your statics all plain old data types - raw pointers - and to initialize them in some appropriate way to point at the instances you need when the program starts up, or when you need them.
最好的做法是将静态数据作为所有普通的旧数据类型 - 原始指针 - 并以适当的方式初始化它们,以指向程序启动时所需的实例,或者何时需要它们。 This puts you in control.
这让你掌控一切。
Your question stated that these types do not need to be compile-time constants. 您的问题表明这些类型不需要是编译时常量。 If so, and you have a multi-threaded program, your objects need to have their state protected from simultaneous access from multiple threads.
如果是这样,并且您有一个多线程程序,则您的对象需要保护其状态不受多个线程的同时访问。 If some of your objects are not thread-safe, then in addition to the object itself you need a mutex object to protect its state, and that has to have the same linkage, and will need initialization.
如果某些对象不是线程安全的,那么除了对象本身之外,还需要一个互斥对象来保护其状态,并且必须具有相同的链接,并且需要初始化。 All this complicates the global state of your program in what could be an unacceptable way.
所有这些使得程序的全局状态变得复杂,这可能是一种不可接受的方式。
I think the other answers here are better, but if you're dead-set on doing it all with headers, you can effectively inline
your object (as you specifically ask) with a simple wrapper function. 我认为这里的其他答案更好,但如果您使用标题完成所有操作,您可以使用简单的包装函数有效地
inline
您的对象(正如您特别要求的那样)。
inline const std::string &get_ten() {
static const std::string ten = "10";
return ten;
}
There will be only one string
, initialized once, and you don't need anything outside of the header file. 将只有一个
string
,初始化一次,并且您不需要头文件之外的任何内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.