Constexpr与宏 [英] Constexpr vs macros

查看:453
本文介绍了Constexpr与宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我应该在哪里使用 macros ,我应该在哪里使用 constexpr ? 他们不是基本相同吗?

Where should I prefer using macros and where should I prefer constexpr? Aren't they basically the same?

#define MAX_HEIGHT 720

vs

constexpr unsigned int max_height = 720;

推荐答案

它们基本不一样吗?

Aren't they basically the same?

不.绝对不.甚至没有关闭.

No. Absolutely not. Not even close.

除了您的宏是intconstexpr unsignedunsigned之外,还有一些重要的区别,并且宏仅具有 one 优势.

Apart from the fact your macro is an int and your constexpr unsigned is an unsigned, there are important differences and macros only have one advantage.

宏由预处理器定义,并且每次发生时都被替换为代码.预处理程序是 dumb ,并且不了解C ++语法或语义.宏会忽略诸如名称空间,类或功能块之类的作用域,因此您不能在源文件中为其他任何名称使用名称.对于定义为适当的C ++变量的常数,情况并非如此:

A macro is defined by the preprocessor and is simply substituted into the code every time it occurs. The preprocessor is dumb and doesn't understand C++ syntax or semantics. Macros ignore scopes such as namespaces, classes or function blocks, so you can't use a name for anything else in a source file. That's not true for a constant defined as a proper C++ variable:

#define MAX_HEIGHT 720
constexpr int max_height = 720;

class Window {
  // ...
  int max_height;
};

最好有一个名为max_height的成员变量,因为它是一个类成员,因此具有不同的作用域,并且不同于命名空间作用域中的成员变量.如果您尝试为成员重用名称MAX_HEIGHT,则预处理器会将其更改为这种无法编译的废话:

It's fine to have a member variable called max_height because it's a class member and so has a different scope, and is distinct from the one at namespace scope. If you tried to reuse the name MAX_HEIGHT for the member then the preprocessor would change it to this nonsense that wouldn't compile:

class Window {
  // ...
  int 720;
};

这就是为什么必须提供宏UGLY_SHOUTY_NAMES来确保它们脱颖而出的原因,并且在命名它们时要格外小心,以免发生冲突.如果您不需要使用宏,则不必担心(也不必阅读SHOUTY_NAMES).

This is why you have to give macros UGLY_SHOUTY_NAMES to ensure they stand out and you can be careful about naming them to avoid clashes. If you don't use macros unnecessarily you don't have to worry about that (and don't have to read SHOUTY_NAMES).

如果您只想在函数内部使用常量,则不能使用宏执行此操作,因为预处理器不知道函数是什么或包含在函数内部意味着什么.要将宏限制为仅文件的特定部分,您需要再次#undef它:

If you just want a constant inside a function you can't do that with a macro, because the preprocessor doesn't know what a function is or what it means to be inside it. To limit a macro to only a certain part of a file you need to #undef it again:

int limit(int height) {
#define MAX_HEIGHT 720
  return std::max(height, MAX_HEIGHT);
#undef MAX_HEIGHT
}

与更为明智的比较:

int limit(int height) {
  constexpr int max_height = 720;
  return std::max(height, max_height);
}

为什么要使用宏?

constexpr变量是变量,因此它实际上存在于程序中,您可以执行常规的C ++操作,例如获取其地址并对其进行绑定.

A constexpr variable is a variable so it actually exists in the program and you can do normal C++ things like take its address and bind a reference to it.

此代码具有未定义的行为:

This code has undefined behaviour:

#define MAX_HEIGHT 720
int limit(int height) {
  const int& h = std::max(height, MAX_HEIGHT);
  // ...
  return h;
}

问题是MAX_HEIGHT不是变量,因此对于std::max的调用,编译器必须创建一个临时int. std::max返回的引用然后可能引用该临时文件,该临时文件在该语句结束后不存在,因此return h访问无效的内存.

The problem is that MAX_HEIGHT isn't a variable, so for the call to std::max a temporary int must be created by the compiler. The reference that is returned by std::max might then refer to that temporary, which doesn't exist after the end of that statement, so return h accesses invalid memory.

使用适当的变量根本就不存在该问题,因为它在内存中的固定位置不会消失:

That problem simply doesn't exist with a proper variable, because it has a fixed location in memory that doesn't go away:

int limit(int height) {
  constexpr int max_height = 720;
  const int& h = std::max(height, max_height);
  // ...
  return h;
}

(实际上,您可能会声明int h而不是const int& h,但问题可能会在更微妙的环境中出现.)

(In practice you'd probably declare int h not const int& h but the problem can arise in more subtle contexts.)

唯一喜欢使用宏的时间是当您需要预处理器理解它的值时,以便在#if条件下使用,例如

The only time to prefer a macro is when you need its value to be understood by the preprocessor, for use in #if conditions, e.g.

#define MAX_HEIGHT 720
#if MAX_HEIGHT < 256
using height_type = unsigned char;
#else
using height_type = unsigned int;
#endif

您不能在此处使用变量,因为预处理器无法理解如何按名称引用变量.它只了解基本的非常基本的东西,例如宏扩展和以#开头的指令(例如#include#define#if).

You couldn't use a variable here, because the preprocessor doesn't understand how to refer to variables by name. It only understands basic very basic things like macro expansion and directives beginning with # (like #include and #define and #if).

如果您想要一个常量可以被预处理器理解,则应该使用预处理器对其进行定义.如果您想为普通C ++代码提供常量,请使用普通C ++代码.

If you want a constant that can be understood by the preprocessor then you should use the preprocessor to define it. If you want a constant for normal C++ code, use normal C++ code.

上面的示例只是为了演示预处理器的条件,但是即使该代码也可以避免使用预处理器:

The example above is just to demonstrate a preprocessor condition, but even that code could avoid using the preprocessor:

using height_type = std::conditional_t<max_height < 256, unsigned char, unsigned int>;

这篇关于Constexpr与宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆