Constexpr与宏 [英] Constexpr vs macros
问题描述
我应该在哪里使用 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.
除了您的宏是int
和constexpr unsigned
是unsigned
之外,还有一些重要的区别,并且宏仅具有 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屋!