简体   繁体   English

定义编译时常量的最佳方法

[英]Best way of defining a compile-time constant

What's the best way of defining a simple constant value in C++11, such that there is no runtime penalty? 在C ++ 11中定义简单常量值的最佳方法是什么,这样就没有运行时惩罚? For example: (not valid code) 例如:(不是有效代码)

// Not ideal, no type, easy to put in wrong spot and get weird errors
#define VALUE 123

// Ok, but integers only, and is it int, long, uint64_t or what?
enum {
     Value = 123
};

// Could be perfect, but does the variable take up memory at runtime?
constexpr unsigned int Value = 123;

class MyClass {
    // What about a constant that is only used within a class, so
    // as not to pollute the parent namespace?  Does this take up
    // memory every time the class is instantiated?  Does 'static'
    // change anything?
    constexpr unsigned int Value = 123;

    // What about a non-integer constant?
    constexpr const char* purpose = "example";
    std::string x;
    std::string metadata() { return this->x + (";purpose=" purpose); }
    // Here, the compiled code should only have one string
    // ";purpose=example" in it, and "example" on its own should not
    // be needed.
};

Edit 编辑

Since I've been told this is a useless question because there's no background behind it, here's the background. 因为我被告知这是一个无用的问题,因为它背后没有背景,这是背景。

I am defining some flags, so that I can do something like this: 我正在定义一些标志,以便我可以这样做:

if (value & Opaque) { /* do something */ }

The value of Opaque won't change at runtime, so as it is only needed at compile time it seems silly to have it end up in my compiled code. Opaque的值在运行时不会改变,因为只有在编译时才需要它才能让它在我的编译代码中结束。 The values are also used inside a loop that runs multiple times for each pixel in an image, so I want to avoid runtime lookups that will slow it down (eg a memory access to retrieve the value of the constant at runtime.) This isn't premature optimisation, as the algorithm currently takes about one second to process an image, and I regularly have over 100 images to process, so I want it to be as fast as possible. 这些值也用在一个循环中,该循环对图像中的每个像素运行多次,所以我想避免运行时查找会降低它的速度(例如,内存访问以在运行时检索常量的值。)这不是'过早优化,因为算法目前需要大约一秒钟来处理图像,我经常有超过100个图像要处理,所以我希望它尽可能快。

Since people are saying this is trivial and not to worry about it, I'm guessing #define is as close as you can get to a literal value, so maybe that's the best option to avoid "overthinking" the problem? 既然人们说这是微不足道的而且不用担心它,我猜测#define就像你可以达到字面值一样接近,所以也许这是避免“过度思考”问题的最佳选择? I guess general consensus is you just hope nobody ever needs to use the word Opaque or the other constants you want to use? 我想普遍的共识是你只希望没有人需要使用Opaque这个词或你想要使用的其他常量?

Indeed, this is trickier than it might appear. 实际上,这比它看起来更棘手。

Just to explicitly restate the requirements: 只是明确重申要求:

  1. There should be no runtime computation. 应该没有运行时计算。
  2. There should be no static, stack, or heap memory allocation except for the actual result. 除实际结果外,不应有静态,堆栈或堆内存分配。 (Allocation of executable code is impossible to forbid, but ensure that any data storage needed by the CPU is private.) (可执行代码的分配不可能被禁止,但要确保CPU所需的任何数据存储都是私有的。)

In C++, expressions can be lvalues or prvalues (before C++11 and in C, rvalues correspond to the relevant concept). 在C ++中,表达式可以是lvalues或prvalues(在C ++ 11和C之前, rvalues对应于相关概念)。 Lvalues refer to objects, hence they can appear on the L eft-hand side of an assignment expression. 左值参考对象,因此它们可以在一个赋值表达式为L EFT-手侧出现。 Object storage and lvalue-ness is what we want to avoid. 对象存储和左值是我们想要避免的。

What you want is an identifier, or id-expression , to evaluate to a prvalue. 你想要的是一个标识符或id-expression来评估prvalue。

Currently, only enumerators can do this, but as you observed, they leave something to be desired. 目前,只有普查员才能做到这一点,但正如您所观察到的那样,他们会留下一些需要的东西。 Each enumeration declaration introduces a new, distinct type, so enum { Value = 123 }; 每个枚举声明都引入了一个新的,不同的类型,因此enum { Value = 123 }; introduces a constant which is not an integer, but its own unique type which converts to int . 引入一个不是整数的常量,但它自己的唯一类型转换int This isn't the right tool for the job, although it works in a pinch. 这不是适合这项工作的合适工具,尽管它适用于工作。

You can use #define , but that's a hack since it avoids the parser completely. 你可以使用#define ,但这是一个黑客,因为它完全避免了解析器。 You have to name it with all capital letters, and then ensure that the same all-caps name isn't used for anything else in the program. 您必须使用所有大写字母命名,然后确保相同的全大写字母名称不用于程序中的任何其他内容。 For library interfaces, such a guarantee is especially onerous. 对于库接口,这种保证尤其繁重。

The next best option is a function call: 下一个最佳选择是函数调用:

constexpr int value() { return 123; }

Careful, though, as constexpr functions can still be evaluated at runtime. 但是,小心,因为constexpr函数仍然可以在运行时进行评估。 You need to jump through one more hoop to express this value as a computation: 你需要跳过一个箍来表达这个值作为计算:

constexpr int value() {
    /* Computations that do not initialize constexpr variables
       (or otherwise appear in a constant expression context)
       are not guaranteed to happen at compile time, even
       inside a constexpr function. */

    /* It's OK to initialize a local variable because the
       storage is only temporary. There's no more overhead
       here than simply writing the number or using #define. */

    constexpr int ret = 120 + 3;
    return ret;
}

Now, you can't refer to the constant as a name, it must be value() . 现在,您不能将常量称为名称,它必须是value() The function call operator might look less efficient, but it's the only current way to completely eliminate storage overhead. 函数调用运算符可能看起来效率较低,但它是完全消除存储开销的唯一当前方法。

You can't go wrong with: 你不能错:

static constexpr const unsigned int Value = 123;

Honestly, though, try not to care about this. 但老实说,尽量不要关心这一点。 Like, really try. 喜欢,真的试试。

I think you should consider the C++11 feature of specifying an underlying type for an enum , which applied to your example would be: 我认为您应该考虑C ++ 11为枚举指定基础类型的功能 ,适用于您的示例将是:

enum : unsigned int { Value = 123 };

this removes one of your two objections to using enums, namely, your inability to control which type would actually be used to represent them. 这消除了您对使用枚举的两个异议之一,即您无法控制实际用于表示它们的类型。 It still doesn't allow non-integeral constants, though. 但它仍然不允许非整数常量。

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

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