Jam*_*son 12 c++ templates c++11
程序A产生编译错误(按预期),因为isFinite使用非整数类型调用.
#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;
}
Run Code Online (Sandbox Code Playgroud)
但是,稍作修改(参见程序B)允许程序编译(Visual Studio 2013)并生成以下输出.
Foo is finite? yes
#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;
}
Run Code Online (Sandbox Code Playgroud)
似乎程序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");
^
Run Code Online (Sandbox Code Playgroud)
我的直觉使我相信编译失败是正确的行为,但很奇怪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;
}
Run Code Online (Sandbox Code Playgroud)
逻辑运算符是否应该在编译时遵守短路评估规则(即,程序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),则其名称显示为可能已评估的表达式的函数将使用odr,除非它是纯虚函数及其名称没有明确限定.[注意:这包括对命名函数(5.2.2)的调用,运算符重载(第13节),用户定义的转换(12.3.2),放置新的分配函数(5.3.4),以及非默认初始化(8.5).选择复制或移动类类型对象的构造函数是使用的,即使调用实际上被实现省略(12.8). - 尾注]
5.13/1
|| 操作员组从左到右.操作数都在上下文中转换为bool(第4条).如果其任一操作数为true,则返回true,否则返回false.与|,||不同 保证从左到右的评估; 此外,如果第一个操作数的计算结果为true,则不计算第二个操作数.
7.1/4
在static_assert声明中,constant-expression应该是一个常量表达式(5.19),可以在上下文中转换为bool(第4条).如果转换后的表达式的值为true,则声明无效.否则,程序格式错误,并且生成的诊断消息(1.4)应包括字符串文字的文本,但不包括不在基本源字符集(2.3)中的字符出现在诊断消息中.
14.7.1/3
除非已明确实例化或明确专门化了函数模板特化,否则在需要存在函数定义的上下文中引用特化时,将隐式实例化函数模板特化.