问题
For member detection in C++14 I used code based on the example here, but it does no seem to work.
A complete example:
#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; }
Compiled using clang++ --std=c++14 test.cpp on OS X, compiler version (clang++ --version): Apple LLVM version 7.0.2 (clang-700.1.81)
The second assert succeeds, but the first fails. Why? I have also tried using decltype(T::substr) instead of typename T::subset, with the same result.
回答1:
Looking for T::substr is not the same as looking for a member function called substr. gcc.godbolt.org example
You can check if a member function exists by using std::declval<T>() and using decltype to get the return type of the member function.
If the member function exists, decltype(...) will be a well-formed expression and will not trigger SFINAE - therefore the the static_assert will work correctly.
#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; }
Note that decltype(std::declval<T>().substr(1, 1)) checks whether T has a substr member that can be called with arguments 1, 1. (This is not guaranteed to be a member function, it could also be a functor data member, for example.)
As said by AndyG in the comments, another possible approach is using decltype to "validate" the type of a member function pointer.
Example:
HasMember_substr<T, void_t< decltype(&T::substr)>
Note that this will not work if the name substr is overloaded, and it is not guaranteed to work with any type in the standard library.
来源:https://stackoverflow.com/questions/34402126/member-detection-using-void-t