编译时是否需要短路评估规则
Are short circuit evaluation rules expected at compile time?
程序A会产生编译错误(正如预期的那样),因为isFinite
是用非整数类型调用的。
程序A
#include <iostream>
class Foo {};
template<typename T>
bool isFinite(const T& t)
{
static_assert(std::is_integral<T>::value, "Called isFinite with a non-integral type");
return false;
}
int main()
{
Foo f;
std::cout << "Foo is finite? " << ((isFinite(f)) ? "yes" : "no") << "n";
return 0;
}
但是,稍微修改一下(请参见程序B),程序就可以编译(Visual Studio 2013)并生成以下输出。
程序B Visual Studio 2013 Ouput
Foo is finite? yes
程序B
#include <iostream>
class Foo {};
template<typename T>
bool isFinite(const T& t)
{
static_assert(std::is_integral<T>::value, "Called isFinite with a non-integral type");
return false;
}
int main()
{
Foo f;
std::cout << "Foo is finite? " << ((true || isFinite(f)) ? "yes" : "no") << "n";
return 0;
}
程序B似乎在逻辑OR运算上短路,并且没有试图编译表达式的其余部分但是,此应用程序不使用g++4.8.3(g++ -std=c++11 -o main main.cpp
)进行编译。我得到以下输出。
main.cpp: In instantiation of 'bool isFinite(const T&) [with T = Foo]':
main.cpp:15:56: required from here
main.cpp:8:2: error: static assertion failed: Called isFinite with a non-integral type
static_assert(std::is_integral<T>::value, "Called isFinite with a non-integral type");
^
我的直觉使我相信编译失败是正确的行为,但令人好奇的是Visual Studio 2013成功编译。我的直觉是基于这样一个事实,即以下代码预计无法编译。
#include <iostream>
struct Foo
{
void doOperation1() {}
void doOperation2() {}
};
struct Bar
{
void doOperationA() {}
void doOperation2() {}
};
template<typename T>
void performOperation(T& t, bool value)
{
if (value)
{
t.doOperation1();
}
else
{
t.doOperation2();
}
}
int main()
{
Foo f;
performOperation(f, true);
performOperation(f, false);
Bar b;
performOperation(b, false); // Fails to compile (as expected)
return 0;
}
重述问题
逻辑运算符是否应该在编译时遵守短路评估规则(即程序B的预期编译行为)?
编译true || (whatever_ill_formed)
时不应出现短路。isFinite<Foo>
是作为表达式的一部分实例化的,在实例化期间应该编译它,在编译期间应该静态断言。在那之后,编译器可能永远不会因为短路而评估isFinite<Foo>(f)
,但静态断言不应该在它的过程中发生
目前尚不清楚Visual Studio 2013编译程序B的原因。标准只允许在模板从未实例化的情况下绕过模板的语法检查。即使在那时,代码仍然不正确,只需要进行诊断。缺陷背后可能是Visual C++中的内部问题,它不允许Microsoft实现constexpr
。
编辑我根据@zneak请求从标准中添加了一些语言律师文本
3.2/3
名称显示为潜在求值表达式的函数为如果它是唯一的查找结果或一组重载函数(3.4、13.3、13.4),除非它是纯函数虚拟函数及其名称未明确限定。[注:此包括对命名函数的调用(5.2.2)、运算符重载(第条13) ,用户定义的转换(12.3.2),用于放置新(5.3.4),以及非默认初始化(8.5)。A选择用于复制或移动类类型的对象的构造函数为即使调用实际上被实现忽略,也会使用odr(12.8).-尾注]
5.13/1
||运算符从左到右分组。操作数既是上下文转换为布尔(第4条)。如果的操作数为true,否则为false。与|、||担保不同从左到右评价;此外,第二个操作数不是如果第一个操作数的求值结果为true,则求值。
7.1/4
在静态资产声明中,常数表达式应为可以在上下文中转换为布尔的常量表达式(5.19)(第4条)。如果在如此转换时表达式的值为真,该声明无效。否则程序是不成形的,并且由此产生的诊断消息(1.4)应包括字符串文字,除了不在基本源中的字符字符集(2.3)不需要出现在诊断中消息
14.7.1/3
除非函数模板专门化已明确实例化或显式专用的函数模板当特殊化为在需要函数定义存在的上下文中引用。
- std::condition_variable::wait()如何评估给定的谓词
- c++11评估顺序(未定义的行为)
- 如何使用"equal to"以外的评估编写开关语句
- 嵌套 if 中没有返回评估
- C 中的短路评估和分配
- 中毒的无效引用和短路表达评估错误或UB
- 短路评估与2017 C
- 如何使"短路评估"在"折叠表达式"中也可用?
- C/C++优化器是否可以决定延迟评估仅用于短路评估的值
- C++短路评估w.r.t优化
- 编译时是否需要短路评估规则
- 如何使用中间规则操作在野牛中创建短路评估
- 如何在用户定义的函数中实现短路评估
- 短路评估vs可读性
- 短路评估是语言缺陷
- &= 运算符的评估(短路)
- C++编译器优化和短路评估
- RPN短路评估
- 将短路评估转换为非短路评估
- 我可以依靠短路评估来检查向量界在c++