int& a; // illegal
if (isfive) {
a = 5;
} else {
a = 4;
}
然而,MSVC似乎认为这是可以的:
int& a = isfive ? 5 : 4;
根据我的理解,MSVC 实际上将条件运算符视为一个单独的表达式,而不是将其展开为 if-else 语句。
在 C++ 中,使用条件运算符初始化引用是否总是有效的?
int& a; // illegal
if (isfive) {
a = 5;
} else {
a = 4;
}
然而,MSVC似乎认为这是可以的:
int& a = isfive ? 5 : 4;
根据我的理解,MSVC 实际上将条件运算符视为一个单独的表达式,而不是将其展开为 if-else 语句。
在 C++ 中,使用条件运算符初始化引用是否总是有效的?
三元运算符不会扩展为if-else
结构(至少在语言层面上不会,虽然实现可能会生成等效的二进制代码)。因此,以下代码是有效的:
int four = 4, five = 5;
int& r = condition? four : five;
问题中的原始示例依赖于微软的扩展,它(不正确地)允许将非const引用绑定到rvalue表达式。
MSVC有一个非标准的“扩展功能”,意思是它允许错误的代码,这是被禁止的很好的理由。
请注意:
int& a = 5;
在标准C++中,这也是不合法的。
但是通常情况下,使用任何可以转换为正确类型的表达式(包括使用条件运算符)都可以用于初始化const
引用。此外,当某些条件满足时,使用正确类型的左值初始化非const
引用,这也是合法的。
你发布的代码无法在VC++ 2010中编译:
错误 1 错误 C2440: 'initializing' : 无法将'int'转换为'int &'
将该行改为:
const int& a = isfive ? 5 : 4;
/Za
(禁用语言扩展)选项? - Ben Voigt条件运算符是一个表达式,而不是语句。像这样初始化引用非常正常。这有点像通过调用函数初始化引用。
请注意,如果将引用绑定到临时对象,则需要将其声明为const
(这是MSVC++愚蠢地忽略的规则)。
const int& r = isfive? 4 : 5;
是可以的,但int& r = isfive? 4 : 5;
不行)。 - David Rodríguez - dribeas这不行
int& a = isfive ? 5 : 4;
除非您将引用“a”声明为const
。
指针+引用技术
感觉这是C++语言的一个限制,可以通过引入新的语言特性来克服。
在那之前,我认为最有效的选择(除非您在if else中执行的操作不仅仅是设置引用,在这种情况下,您可以使用三元运算符?
)是使用指针,然后将引用设置为指针,以避免在稍后每次使用变量时进行多个解引用:
main.cpp
#include <iostream>
int main(int argc, char **argv) {
(void)argv;
int x = 1;
int y = 2;
int *ptr;
if (argc > 1) {
ptr = &x;
} else {
ptr = &y;
}
// One pointer dereference here, I don't see how to get rid of this.
int &z = *ptr;
// No pointer dereference on any of the below usages.
z = 3;
std::cout << x << std::endl;
std::cout << y << std::endl;
std::cout << z << std::endl;
}
编译:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
运行:
./main.out
输出:
1
3
3
再次运行:
./main.out a
输出:
3
2
3
如果在编译时已知 if 条件,你当然可以使用预处理器或者更好的 C++17 的 if constexpr
:
相关链接:C++ 中如何在编译时进行 if / else 判断?
相关链接:如何先声明引用再进行初始化?
auto& ref = [&]() -> int& { if (cond) return x; return y;}();
- Quest它是运算符,表达式的一部分,而不是语句。即使只是短暂的时间,你也不能让引用未初始化 ;-)