Member definition with void_t

To detect members in C ++ 14, I used code based on the example here , but it doesn't seem to work.

Full 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 statement succeeds, but the first fails. What for? I also tried using decltype(T::substr) instead of typename T::subset with the same result.

+7
c ++ c ++ 14
source share
1 answer

Finding 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 using std::declval<T>() and using decltype to get the return type of the member function.

If a member function exists, decltype(...) will be a well-formed expression and will not call SFINAE, so 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 if T a substr member that can be called with arguments 1, 1 . (This is not guaranteed as a member function; it can also be an element of a functor data.)


As AndyG said in the comments, another possible approach uses decltype to "check" the type of a member function pointer.

Example:

 HasMember_substr<T, void_t< decltype(&T::substr)> 

Please note that this will not work if substr overloaded, and does not guarantee operation with any type in the standard library .

+11
source share

All Articles