Edit, in order to avoid confusion:
decltype
does not accept two arguments. See answers.
以下两个结构可用于在编译期间检查类型T上的成员函数是否存在:
// Non-templated helper struct:
struct _test_has_foo {
template<class T>
static auto test(T* p) -> decltype(p->foo(), std::true_type());
template<class>
static auto test(...) -> std::false_type;
};
// Templated actual struct:
template<class T>
struct has_foo : decltype(_test_has_foo::test<T>(0))
{};
我认为这个想法是在检查成员函数的存在时使用SFINAE,因此在p-> foo()无效的情况下,只定义了返回std :: false_type的省略号test.否则,第一个方法是为T *定义的,并将返回std :: true_type.实际的“切换”发生在第二个类中,它继承自test返回的类型.与使用is_same和类似的东西的不同方法相比,这看起来更聪明和“轻量级”.
带有两个参数的decltype首先让我感到惊讶,因为我认为它只是获得表达式的类型.当我看到上面的代码时,我认为它类似于“尝试编译表达式并始终返回第二种类型.如果表达式无法编译则失败”(所以隐藏此专业化; SFINAE).
但:
然后我想我可以使用这个方法来编写任何“is valid expression”检查器,只要它依赖于某种类型T.示例:
...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
这个,我想,当且仅当bar被定义为接受T作为第一个参数(或者如果T是可转换的,等等)时,这将返回std :: true_type,即:如果bar(* p)将编译如果它是在某些上下文中写的,其中p被定义为类型T *.
但是,上面的修改总是评估为std :: false_type.为什么是这样?我不想用一些复杂的不同代码修复它.我只是想知道为什么它不像我预期的那样工作.很明显,带有两个参数的decltype与我想的不同.我找不到任何文件;只用一个表达式解释它到处都是.
解决方法:
它是以逗号分隔的表达式列表,其类型与列表中最后一个表达式的类型相同.它通常用于验证第一个表达式是否有效(可编译,想想SFINAE),第二个用于指定在第一个表达式有效时应返回decltype.