对于C ++ 14中的成员检测,我使用了基于示例here的代码,但它似乎没有用。
一个完整的例子:
#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; }
在OS X上使用clang++ --std=c++14 test.cpp
进行编译,编译器版本(clang++ --version
):Apple LLVM version 7.0.2 (clang-700.1.81)
第二个断言成功,但第一个断言失败。为什么?我也尝试使用decltype(T::substr)
代替typename T::subset
,结果相同。
答案 0 :(得分:11)
查找T::substr
与查找名为substr
的成员函数不同。 gcc.godbolt.org example
您可以使用std::declval<T>()
并使用decltype来检查成员函数是否存在,以获取成员函数的返回类型。
如果成员函数存在,decltype(...)
将是格式正确的表达式,不会触发SFINAE - 因此static_assert
将正常工作。
#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; }
请注意,decltype(std::declval<T>().substr(1, 1))
会检查T
是否有可以使用参数substr
调用的1, 1
成员。 (此不保证是成员函数,例如,它也可以是仿函数数据成员。)
正如AndyG在评论中所说,另一种可能的方法是使用decltype
来验证&#34;成员函数指针的类型。
示例:
HasMember_substr<T, void_t< decltype(&T::substr)>
请注意,如果名称substr
已超载且is not guaranteed to work with any type in the standard library已成功,则此功能无效。