简体   繁体   English

非积分常数

[英]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变量。

  • Is there something in the c++ standard that says the extern version should work or am I just lucky it works with GCC? c ++标准中是否有一些内容表明外部版本应该有用,或者我很幸运它与GCC一起使用?
  • Is there a compelling reason not to allow inline variables? 是否有令人信服的理由不允许内联变量?
  • Is there a better way with c++03 or will there be a better way in c++0x? c ++ 03有更好的方法还是c ++ 0x会有更好的方法?

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。

Here's how you can do it: 这是你如何做到的:

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.

相关问题 非整数常量在C ++中如何工作? - How do non-integral constants work in C++? 非集成静态数据的类内初始化 - in-class initialization of non-integral static data 初始化类的静态const非整数数据成员 - Initialize a static const non-integral data member of a class 用私有成员初始化静态const非整数类成员 - Initialise static const, non-integral, class member with a private member 错误:数组'u'的大小具有非整数类型'double'| - error: size of array ‘u’ has non-integral type ‘double’| 静态const(非整数)成员初始化语法背后的基本原理? - Rationale behind static const (non-integral) member initialization syntax? "整型非类型参数和非整型非类型的模板偏特化,g++和clang的区别" - Template partial specialization for integral non-type parameters and non-integral non-types, difference between g++ and clang Visual Studio 2013 CTP是否支持非整数类型的类内静态const初始化程序? - Does Visual Studio 2013 CTP support in-class static const initializers for non-integral types? 为什么在类中初始化的非整数静态数据成员必须是constexpr? - Why must non-integral static data members initialized in the class be constexpr? C ++非整体模板Const初始化,需要在ClassName之前使用init-declarator - C++ Non-Integral template Const Initialization expected init-declarator before ClassName
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM