C++ 基于void\u t的构件检测

C++ 基于void\u t的构件检测,c++,c++14,C++,C++14,对于C++14中的成员检测,我使用了基于示例的代码,但它似乎不起作用 一个完整的例子: #include <string> template <typename...> using void_t = void; template <typename, typename = void> class HasMember_substr : public std::false_type {}; template <typename T> class H

对于C++14中的成员检测,我使用了基于示例的代码,但它似乎不起作用

一个完整的例子:

#include <string>

template <typename...>
using void_t = void;

template <typename, typename = void> class HasMember_substr : public std::false_type {};
template <typename T> class HasMember_substr<T, void_t<typename T::substr>> : public std::true_type {};

template <typename, typename = void> class HasMember_fff : public std::false_type {};
template <typename T> class HasMember_fff<T, void_t<typename T::fff>> : public std::true_type {};

static_assert(HasMember_substr<std::string>::value, "");
static_assert(!HasMember_fff<std::string>::value, "");

int main() { return 0; }
#包括
模板
使用void\u t=void;
模板类HasMember\u substr:public std::false\u type{};
模板类HasMember\u substr:public std::true\u type{};
模板类HasMember\u fff:public std::false\u type{};
模板类HasMember\u fff:public std::true\u type{};
静态断言(HasMember\u substr::value,“”);
静态断言(!HasMember\u fff::value,“”);
int main(){return 0;}
在OS X上使用
clang++--std=c++14 test.cpp编译,编译器版本(
clang++--version
):
Apple LLVM版本7.0.2(clang-700.1.81)


第二个断言成功,但第一个断言失败。为什么?我还尝试使用
decltype(T::substr)
而不是
typename T::subset
,得到了相同的结果。

查找
T::substr
与查找名为
substr
的成员函数不同

通过使用和获取成员函数的返回类型,可以检查成员函数是否存在

如果成员函数存在,
decltype(…)
将是一个格式良好的表达式,不会触发SFINAE-因此
静态断言将正常工作

#include <string>
#include <type_traits>
#include <utility>

template <typename...>
using void_t = void;

template <typename, typename = void> 
class HasMember_substr : public std::false_type {};

template <typename T> 
class HasMember_substr<T, void_t<
     decltype(std::declval<T>().substr(1, 1))>
> : public std::true_type {};

static_assert(HasMember_substr<std::string>::value, "");

int main() { return 0; }

请注意,如果名称
substr
被重载,并且它与
T{}不同,那么这将不起作用。

T::substr
在您的实现中是一个重载函数吗?(这是允许的。)您已经复制了一个测试类型的示例,并期望相同的代码用于测试成员函数。这显然行不通
std::string::substr
不是类型,因此
typename T::substr
显然是胡说八道。您应该复制测试预增量的示例。我可能会简化为
HasMember\u substr
@并且,如果名称
substr
重载,这将不起作用。“如果名称substr重载,这将不起作用”…因此。准确地说,使用
decltype(std::declval().substr(0,0))的版本
不检查
t
是否具有
substr
成员函数。它检查
T
是否具有可以用参数
0,0
调用的
substr
成员。那是不一样的。例如,它允许
substr
成为函子数据成员。另一个例子:它不允许
substr
成为不带参数的成员函数。这很好,可能更接近OP想要的,但在你的答案中更清楚地说明它在做什么可能会有所帮助。另外,我建议
1,1
排除解释为空指针常量的可能性。我不认为需要小心突出显示hvd的点。这是一个有趣的事实,值得指出,但没有什么值得谨慎的。关键是测试
decltype(std::declval().substr(1,1))
在您关心的所有情况下都有效,您不需要关心它是否是一个函数(也不需要谨慎)。
HasMember_substr<T, void_t< decltype(&T::substr)>