在我看来,拥有"总是返回5的功能"正在破坏或淡化"调用函数"的含义.必须有一个原因,或者需要这种能力,或者它不会出现在C++ 11中.为什么会这样?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
Run Code Online (Sandbox Code Playgroud)
在我看来,如果我编写了一个返回字面值的函数,并且我进行了代码审查,有人会告诉我,我应该声明一个常量值而不是写回返5.
我上课了
class foo {
public:
foo();
foo( int );
private:
static const string s;
};
Run Code Online (Sandbox Code Playgroud)
在s源文件中初始化字符串的最佳位置在哪里?
在2016年奥卢ISO C++标准会议上,一项名为Inline Variables的提案被标准委员会投票选为C++ 17.
通俗地说,什么是内联变量,它们如何工作以及它们对什么有用?如何声明,定义和使用内联变量?
C++ 17更新:
static constexpr变量是隐式的,inline因此不需要外部定义.
原始问题:
假设我有一个常量列表,例如
struct Cls {
static constexpr int N = 32;
static constexpr int M = 64;
};
Run Code Online (Sandbox Code Playgroud)
这当然表明我为这些添加定义以避免可能发生的ODR使用问题,因此我需要:
constexpr int Cls::N;
constexpr int Cls::M;
Run Code Online (Sandbox Code Playgroud)
为什么要我喜欢这个了
struct Cls {
enum : int {
N = 32,
M = 64
};
};
Run Code Online (Sandbox Code Playgroud)
从而节省了我的ODR使用难题N,M并且更真实地只是常量而不是它们自己的对象(如果这只是标题,那就更大了)并且更短.enum : long long如果需要,我可以明确指定类型或其他任何东西.第一个有什么优势?
我习惯用定义我的常量enum { my_const = 123; },因为在类中,使用static constexpr需要在类定义之外的一些代码(参见这个问题).但是 - 功能体呢?最近我注意到人们只是constexpr在他们的功能中有变量(const实际上甚至没有打扰他们),我想知道我是不是一个傻瓜谁是我的时代背后
int foo(int x)
{
enum : int { bar = 456 };
return x + bar;
}
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是:在函数体中使用枚举而不是constexpr变量有什么好处吗?
我正在阅读lippman的c ++入门,其中p.他们给出了这个:
class Account {
private:
static constexpr int period = 30;
double daily_tbl[period];
}
Run Code Online (Sandbox Code Playgroud)
如果成员仅在编译器可以替换成员的值的上下文中使用,则不需要单独定义初始化的const或constexpr静态.但是,如果我们在无法替换值的上下文中使用该成员,则必须有该成员的定义.
也:
例如,如果我们将Account :: period传递给一个带有const int&的函数,则必须定义period.
所以我尝试添加这样一个功能:
class Account {
private:
static constexpr int period = 30;
double daily_tbl[period];
void foo(const int &i) { ; }
void bar() { foo(period); } //no error?
};
Run Code Online (Sandbox Code Playgroud)
在那里我添加了一个带有const int&的函数.我也没有为period变量添加任何定义.但我仍然没有错,因为他们说我应该得到.为什么不?
这可能是有点不寻常的问题,因为它要求给一个简短的回答更充分的说明了另一个问题以及与之相关的C++标准11的某些方面.
为便于参考,我将在此总结引用的问题.OP定义了一个类:
struct Account
{
static constexpr int period = 30;
void foo(const int &) { }
void bar() { foo(period); } //no error?
};
Run Code Online (Sandbox Code Playgroud)
并且想知道为什么他没有得到关于他使用类内初始化静态数据成员的错误(一本书提到这是非法的).Johannes Schaub的回答指出:
尽管我依赖这个答案的来源和有效性,但我真的不喜欢它,因为我个人觉得它太神秘了,所以我试图找出一个更有意义的答案,只取得部分成功.相关似乎是§9.4.2/ 4:
"有应是静态数据成员中的恰好一个定义ODR使用的程序中的(3.2); 没有诊断是必需的 " [重点是矿]
这让我更接近这一点.这就是§3.2/2定义了一个使用了odr的变量:
"名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式(5.19)中的要求的对象,并且立即应用左值到右值转换(4.1)" [重点是我的]
在OP的问题中,变量period显然满足出现在常量表达式中的要求,即constexpr变量.因此必须在第二个条件中找到原因:" 并立即应用左值到右值的转换(4.1) ".
这是我解释标准的麻烦.这第二个条件究竟意味着什么?它涵盖了哪些情况?这是否意味着如果从函数返回静态constexpr变量并非使用 odr(因此可以在类中初始化)?
更一般地说:你可以用静态constexpr变量做什么,这样你可以在课堂上初始化它?
在下面,static constexpr成员L在类中初始化A,然后通过值或(通用)引用传递.后者在Clang中失败但在GCC中失败,并且成员/非成员函数的行为略有不同.更详细:
#include <iostream>
using namespace std;
struct A
{
static constexpr size_t L = 4;
template <typename T>
void member_ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void member_val(T x) { cout << x << endl; }
};
template <typename T>
void ref(T&& x) { cout << std::forward<T>(x) << endl; }
template <typename T>
void val(T x) { cout << x << endl; }
int main ()
{
A().member_ref(A::L); …Run Code Online (Sandbox Code Playgroud) 编辑这不是对静态类成员的未定义引用的重复.那个问题探讨了问题的原因(我在下面解释).在这里,我正在寻找与那些问题的答案中提出的解决方案不同的解决方案(这意味着更改constexpr要使用的变量的声明/定义- 主要是通过在编译单元中添加定义).
我已经创建了一个小的可变参数模板函数make_string()来生成std::string任意数量的io-able参数,如下所示.
using std::ostringstream; // just for this example
inline ostringstream&write(ostringstream&ostr, const char*x)
{ if(x) ostr<<x; return ostr; }
template<class T>
inline ostringstream&write(ostringstream&ostr, T const&x)
{ ostr<<x; return ostr; }
inline ostringstream&write(ostringstream&ostr) noexcept
{ return ostr; }
template<class T, class... R>
inline ostringstream&write(ostringstream&ostr, T const&x, R&&... r)
{ return write(write(ostr,x), std::forward<R>(r)...); }
inline std::string make_string(const char*text)
{ return {text?text:""}; }
inline std::string …Run Code Online (Sandbox Code Playgroud)