很明显 constexpr 意味着 const,因此很常见:
constexpr int foo = 42; // no const here
但是如果你写:
constexpr char *const str = "foo";
如果传递了 -Wwrite-string 标志,GCC 将生成“警告:不推荐从字符串常量到‘char*’的转换”。
写作:
constexpr const char *const str = "foo";
解决问题。
那么 constexpr const 和 constexpr 真的一样吗?
问题在于,在变量声明中,
constexpr
始终将const
-ness应用于声明的对象; const
另一方面可以适用于不同的类型,具体取决于位置。
因此
constexpr const int i = 3;
constexpr int i = 3;
是等价的;
constexpr char* p = nullptr;
constexpr char* const p = nullptr;
是等价的;两者都使
p
成为指向 const
的 char
指针。
constexpr const char* p = nullptr;
constexpr const char* const p = nullptr;
是等价的。
constexpr
使 p
成为 const
指针。 const
中的const char *
使p
指向const char
。
您看到的错误消息与
constexpr
关键字本身无关。
像“foo”这样的字符串文字,如:
somefunction("foo");
这个字符串文字的类型是
const char *
。以下声明:
char *const str = "foo";
这会尝试将
const char *
值分配给 char *
值。生成的 char *
值是不可变的、恒定的,但此时错误已经发生:尝试将 const char *
转换为 char *
。
示例中的
constexpr
关键字只是一种干扰,与错误无关。
没有。说它们是相同的意味着,如果不生成与 const 版本功能相同的代码,不使用 const 就不会有效。
我发现这对于创建安全单例很有用。我还没有完全探索这一点,并且希望非常量 constexpr 还有其他有效的用途。
作为示例,以下代码需要非 const constexpr:
从变量的全局定义开始:
int global_int_;
现在我们可以创建一个 constexpr 函数来返回对其的引用:
constexpr int& get_global()
{
return global_int_;
}
现在我们可以在其他地方使用该引用:
int main()
{
constexpr int& i{ get_global() };
// do stuff with i
return 0;
}
我们现在可以使用
i
作为非常量 int。如果 const 被隐含,这是不可能的。
由于非常量 constexpr 是有效的,如果您使用的 constexpr 需要为 const,则需要显式声明它。