编辑,以避免混淆:
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()
无效,则只定义test
返回 的省略号版本。std::false_type
否则为第一个方法定义T*
并将返回std::true_type
。实际的“切换”发生在第二个类中,它继承自test
. 与使用类似方法的不同方法相比,这似乎很聪明且“轻量级” is_same
。
with two arguments 首先让decltype
我感到惊讶,因为我认为它只是获取表达式的类型。当我看到上面的代码时,我认为它类似于“尝试编译表达式并始终返回第二个的类型。如果表达式编译失败,则失败”(所以隐藏这个专业化;SFINAE)。
但:
然后我想我可以使用这种方法来编写任何“有效表达式”检查器,只要它依赖于某种类型T
。例子:
...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
所以我认为,这将返回一个std::true_type
当且仅当bar
被定义接受 aT
作为第一个参数(或者如果T
是可转换的,等等......),即:如果它是在定义类型bar(*p)
的某些上下文中编写的,则将编译.p
T*
但是,上面的修改总是计算为std::false_type
。为什么是这样?我不想用一些复杂的不同代码来修复它。我只是想知道为什么它不能像我预期的那样工作。显然,decltype
有两个论点的工作方式与我想象的不同。我找不到任何文件;到处都只能用一种表达方式来解释。