【发布时间】:2015-04-24 10:20:20
【问题描述】:
程序 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 输出
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 的预期编译行为是什么)?
【问题讨论】:
-
@TonyD 也许我误读了文档,但here 似乎 unspecialized 案例总是返回
false。 -
@MattMcNabb 如果我将
has_infinity替换为硬编码的true,我会得到相同的行为 -
@MattMcNabb 我不小心给你加了标签,我更正了我的评论
-
James/Matt:是的 - 非专业价值的好点。无论如何,短路评估是关于不评估错误路径...在这种情况下,函数调用
std::isfinite(Zoo)在编译时是 invalid - 没有这样的重载 - 所以我看不到编译器有义务接受它。 -
@MattMcNabb 公平点,我用
true替换了numeric_limits的用法