我正在读一本解释C ++特征的书,并且有一个C ++ type_traits标题的示例,其中有一个奇怪的?:
用法,这里是来自相应的/ usr / include / c ++ / ...文件的引用:
template<typename _Tp, typename _Up>
static __success_type<typename decay<decltype
(true ? std::declval<_Tp>()
: std::declval<_Up>())>::type> _S_test(int);
撇开给定声明的目的,?:
运算符用法在这段代码中让我感到困惑。如果第一个操作数为true
,则将始终选择std::declval<_Tp>()
作为评估结果。
该declval操作数选择实际上如何工作?
编辑:最初阅读Nicolai M. Josuttis&#34; C ++标准库:教程和参考,第2版。&#34;,第125页。但与我的GCC头文件相比,它以略微简化的形式给出。
答案 0 :(得分:10)
在表达式true ? std::declval<_Tp>() : std::declval<_Up>()
中,始终选择第一个选项,但整个表达式必须是有效的表达式。因此std::declval<_Up>()
必须有效,这意味着_Up
必须是可接受零参数的可调用对象。除此之外,_Tp()
和_Up()
必须返回相同的类型(或者其中一种类型必须可以隐式转换为另一种类型),否则三元迭代器将无法选择返回值。
这种技术称为SFINAE(替换失败不是错误)。这个想法是,如果模板实例化失败,那么它不是错误,只是忽略了这个模板,编译器会搜索另一个模板。
答案 1 :(得分:3)
这里的想法是?:
要求第二个和第三个操作数具有相同的类型,或者一个类型可以转换为另一个类型。
否则,函数的实例化将失败,并选择一些其他重载。