Consexpr 与宏 [英] Constexpr vs macros

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

问题描述

我应该在哪里使用 macros,我应该在哪里使用 constexpr?不是基本一样吗?

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

#define MAX_HEIGHT 720

constexpr unsigned int max_height = 720;

推荐答案

他们不是基本一样吗?

Aren't they basically the same?

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

No. Absolutely not. Not even close.

除了你的宏是一个 int 而你的 constexpr unsigned 是一个 unsigned 之外,还有一些重要的区别,宏只有 一个优势.

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.

宏由预处理器定义,每次出现时都简单地替换到代码中.预处理器是哑巴,不理解 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>;

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

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