编辑,为了避免混淆:
decltype
不接受两个参数。请参见答案。
以下两个结构体可用于在编译时检查类型 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)。但是:
然后我想我可以使用这种方法编写任何“有效表达式”检查器,只要它依赖于某种类型
T
。例如:...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
我原本以为这样会返回一个std::true_type
,只有当bar
接受T
作为第一个参数时才会返回(或者如果T
可转换等),也就是说:如果在某个上下文中定义了类型为T*
的p
,那么bar(*p)
将编译通过。
然而,进行上述修改后,结果总是评估为std::false_type
。为什么呢?我不想用一些复杂的不同代码来修复它。我只想知道为什么它不能按照我的预期工作。显然,带有两个参数的decltype
与我想象的不同。我找不到任何文档;它只在每个地方用一个表达式解释。