How can you check whether a templated class has a member function?
Asked Answered
M

34

631

Is it possible to write a template that changes behavior depending on if a certain member function is defined on a class?

Here's a simple example of what I would want to write:

template<class T>
std::string optionalToString(T* obj)
{
    if (FUNCTION_EXISTS(T->toString))
        return obj->toString();
    else
        return "toString not defined";
}

So, if class T has toString() defined, then it uses it; otherwise, it doesn't. The magical part that I don't know how to do is the "FUNCTION_EXISTS" part.

Mesic answered 2/11, 2008 at 20:10 Comment(2)
Of course it goes without saying that the template answer(s) below only work with compile-time information, i.e. T must have toString. If you pass in a subclass of T that does define toString, but T does not, you will be told toString is not defined.Footway
Note that C++20 now permits to do that with concepts. See #58395056 and en.cppreference.com/w/cpp/language/constraintsTraver
F
383

Yes, with SFINAE you can check if a given class does provide a certain method. Here's the working code:

#include <iostream>

struct Hello
{
    int helloworld() { return 0; }
};

struct Generic {};    

// SFINAE test
template <typename T>
class has_helloworld
{
    typedef char one;
    struct two { char x[2]; };

    template <typename C> static one test( decltype(&C::helloworld) ) ;
    template <typename C> static two test(...);    

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
    
int main(int argc, char *argv[])
{
    std::cout << has_helloworld<Hello>::value << std::endl;
    std::cout << has_helloworld<Generic>::value << std::endl;
    return 0;
}

I've just tested it with Linux and gcc 4.1/4.3. I don't know if it's portable to other platforms running different compilers.

Fireeater answered 2/11, 2008 at 21:15 Comment(22)
Ach you beat me to it! It's a very nice trick this one (confirmed working with GCC 4.1 on Mac OSX 10.5)Maraud
Although, I used the following for 'one' and 'two': typedef char Small; class Big{char dummy[2];} to ensure no ambiguity about platform dependent variable size.Maraud
I doubt it exists on earth a platform with the sizeof(char) == sizeof(long)Fireeater
Well indeed, but strictly it's not guaranteed if you're being really standards correct. (P.S. I have seen platforms where this is the case, but the compilers would choke on that code anyway ;) )Maraud
I'm not entirely sure, but I don't think this is portable. typeof is a GCC extension, this will not work on other compilers.Protoxylem
If you're really concerned about that size that could match, using boost::is_same may be more robust.Protoxylem
Leon, do you think is possible to ride of typeof() using a different method ? I was thinking about tr1::results_of...Fireeater
typeof isn't needed - char[sizeof(&C::helloworld)] works as well. And to avoid sizeof(long)==sizeof(char), use a struct { char[2] };. It must have a size >=2Crutchfield
I reworked this solution a bit so it doesn't require typeof. Check out my answer near the bottom of this page. Actually what I did was to merge Nicola's and Johannes's answers and try to give helpful names to all the constructs. Hope it helps.Firn
Trivial, but took me a while to figure out: replace typeof by decltype when using C++0x, e.g., via -std=c++0x.Endeavor
@Endeavor Thank you sir this fixed my compiler error under Linux for C++0x.Hedi
decltype does replaces typeof in C++0x. However the solution does not compile with decltype (decltype cannot resolve address of overloaded function).Mohandas
I'm not sure why your solution has two template parameters (T in the class and C in the method).Playground
@Playground The "extra" typename C on the test methods is required because of the way SFINAE works. If you would use T the compiler would be unable to instantiate the template at all and the code would not compile (because there is no valid version of has_helloworld<Generic>).Stereochromy
@Mohandas It should work if you use decltype(C::helloworld)* instead of decltype(&C::helloworld).Stereochromy
How to check existence of helloworld, if it is a template of function? typeof(&C::helloworld) will fail in this caseRecondite
This is also won't work when helloworld is overloaded.Recondite
If some confused about ..., look at #39664953Hawsehole
@NicolaBonelli, wrong. Some Cray Systems have processors that use 64 registers of 64 bit each and they do not offer bytes. Their C/C++ compilers integer types are all 64 bits. Those machines are very fast at calculating matrices and such, but slow at compiling code (which requires bytes and thus lots of shifting... in the end, though, still way faster that your puny x86 compatible processor... :-) )Alviani
I've put decltype instead of typeof, and the example works. But if I try to detect begin with vector<int> it doesn't work. (of course I've written &C::begin and I've also tested Max Truxa's suggestion with decltype(C::begin)*, but no way. what can be done in this case ?Maestas
@Maestas I've just had this issue myself and someone posted an answer here: https://mcmap.net/q/24111/-why-using-sfinae-to-find-if-a-method-exists-fails-with-std-vector-beginAplomb
What's the difference of above solution and std::is_member_function_pointer (en.cppreference.com/w/cpp/types/is_member_function_pointer) ?Timotheus
S
304

This question is old, but with C++11 we got a new way to check for a functions existence (or existence of any non-type member, really), relying on SFINAE again:

template<class T>
auto serialize_imp(std::ostream& os, T const& obj, int)
    -> decltype(os << obj, void())
{
  os << obj;
}

template<class T>
auto serialize_imp(std::ostream& os, T const& obj, long)
    -> decltype(obj.stream(os), void())
{
  obj.stream(os);
}

template<class T>
auto serialize(std::ostream& os, T const& obj)
    -> decltype(serialize_imp(os, obj, 0), void())
{
  serialize_imp(os, obj, 0);
}

Now onto some explanations. First thing, I use expression SFINAE to exclude the serialize(_imp) functions from overload resolution, if the first expression inside decltype isn't valid (aka, the function doesn't exist).

The void() is used to make the return type of all those functions void.

The 0 argument is used to prefer the os << obj overload if both are available (literal 0 is of type int and as such the first overload is a better match).


Now, you probably want a trait to check if a function exists. Luckily, it's easy to write that. Note, though, that you need to write a trait yourself for every different function name you might want.

#include <type_traits>

template<class>
struct sfinae_true : std::true_type{};

namespace detail{
  template<class T, class A0>
  static auto test_stream(int)
      -> sfinae_true<decltype(std::declval<T>().stream(std::declval<A0>()))>;
  template<class, class A0>
  static auto test_stream(long) -> std::false_type;
} // detail::

template<class T, class Arg>
struct has_stream : decltype(detail::test_stream<T, Arg>(0)){};

Live example.

And on to explanations. First, sfinae_true is a helper type, and it basically amounts to the same as writing decltype(void(std::declval<T>().stream(a0)), std::true_type{}). The advantage is simply that it's shorter.
Next, the struct has_stream : decltype(...) inherits from either std::true_type or std::false_type in the end, depending on whether the decltype check in test_stream fails or not.
Last, std::declval gives you a "value" of whatever type you pass, without you needing to know how you can construct it. Note that this is only possible inside an unevaluated context, such as decltype, sizeof and others.


Note that decltype is not necessarily needed, as sizeof (and all unevaluated contexts) got that enhancement. It's just that decltype already delivers a type and as such is just cleaner. Here's a sizeof version of one of the overloads:

template<class T>
void serialize_imp(std::ostream& os, T const& obj, int,
    int(*)[sizeof((os << obj),0)] = 0)
{
  os << obj;
}

The int and long parameters are still there for the same reason. The array pointer is used to provide a context where sizeof can be used.

Showman answered 6/2, 2012 at 0:27 Comment(13)
The advantage of decltype over sizeof is also that a temporary is not introduced by specially crafted rules for function calls (so you don't have to have access rights to the destructor of the return type and won't cause an implicit instantiation if the return type is a class template instantiation).Pouched
Microsoft has not implemented Expression SFINAE in it's C++ compiler yet. Just figure I might help save some people time, as I was confused why this wasn't working for me. Nice solution though, can't wait to use it in Visual Studio!Tannenbaum
It has to be said, that static_assert(has_stream<X, char>() == true, "fail X"); will compile and not assert because char is convertable to int, so if that behavior is not wanted and want that all argument types match i dont know how that can be achieved?Woorali
How do you use it with enable_if?Elswick
If you are as puzzled as I was on the two arguments to decltype: decltype really only takes one; the comma is an operator here. See #16045014Sumac
This works perfectly in situations that require complete types, but in situations that don't this will give false negatives for incomplete (forward declared) types. I added a sfinae_false counterpart and used a return type on the long override that detected for the presence of a destructor. This excluded types that were still incomplete or didn't have public destructors. Excluding non-public destructors was acceptable for me.Komarek
Is there a reason why you wouldn't use sizeof(os<<obj), if not embedding it as a template argument or a return type deduced from std::enable_if? It seems like an aesthetic choice, but if it was, the int pointer seems strange to me. @Elswick - I believe it would be auto ... -> typename std::enable_if<sizeof(os << obj), void>::type {...}.Evan
@Showman It is a great answer (+1), but in your first example (serialize), you should not use the types int and long to guide the overload resolution. It does not compile if int and long have the same size, because the call to the overloaded function (serialize_imp) is ambiguous. You can keep the type int for the first overload, and replace long by the type wrapper defined this way: struct wrapper { constexpr wrapper(int a) {++a;} }; .Leucocyte
How has nobody remarked on the fact that this is not a C++11 solution at all? Return type deduction is a C++14 feature.Proven
Why does this example use streams at all? Is that really necessary?Susysuter
@Proven trailing return type declaration is C++11Gunas
Remark: I assume that the void cast is needed in decltype(void(std::declval<T>().stream(a0)), std::true_type{}) because it's possible that the return type has operator, overloaded. ■ Related c++ - Is this a valid way of performing "Expression SFINAE" in C++03? - Stack Overflow for a (possibly non-conforming) way to perform expression SFINAE on C++03.Gunas
Why exploit SFINAE if your compiler has decltype support??? However, for correct SFINAE exploit see Check member functionPalaearctic
M
207

C++20 - requires expressions

With C++20 come concepts and assorted tools such as requires expressions which are a built-in way to check for a function existence. With them you could rewrite your optionalToString function as follows:

template<class T>
std::string optionalToString(T* obj)
{
    constexpr bool has_toString = requires(const T& t) {
        t.toString();
    };

    if constexpr (has_toString)
        return obj->toString();
    else
        return "toString not defined";
}

Pre-C++20 - Detection toolkit

N4502 proposes a detection toolkit for inclusion into the C++17 standard library that eventually made it into the library fundamentals TS v2. It most likely won't ever get into the standard because it has been subsumed by requires expressions since, but it still solves the problem in a somewhat elegant manner. The toolkit introduces some metafunctions, including std::is_detected which can be used to easily write type or function detection metafunctions on the top of it. Here is how you could use it:

template<typename T>
using toString_t = decltype( std::declval<T&>().toString() );

template<typename T>
constexpr bool has_toString = std::is_detected_v<toString_t, T>;

Note that the example above is untested. The detection toolkit is not available in standard libraries yet but the proposal contains a full implementation that you can easily copy if you really need it. It plays nice with the C++17 feature if constexpr:

template<class T>
std::string optionalToString(T* obj)
{
    if constexpr (has_toString<T>)
        return obj->toString();
    else
        return "toString not defined";
}

C++14 - Boost.Hana

Boost.Hana apparently builds upon this specific example and provides a solution for C++14 in its documentation, so I'm going to quote it directly:

[...] Hana provides a is_valid function that can be combined with C++14 generic lambdas to obtain a much cleaner implementation of the same thing:

auto has_toString = hana::is_valid([](auto&& obj) -> decltype(obj.toString()) { });

This leaves us with a function object has_toString which returns whether the given expression is valid on the argument we pass to it. The result is returned as an IntegralConstant, so constexpr-ness is not an issue here because the result of the function is represented as a type anyway. Now, in addition to being less verbose (that's a one liner!), the intent is much clearer. Other benefits are the fact that has_toString can be passed to higher order algorithms and it can also be defined at function scope, so there is no need to pollute the namespace scope with implementation details.

Boost.TTI

Another somewhat idiomatic toolkit to perform such a check - even though less elegant - is Boost.TTI, introduced in Boost 1.54.0. For your example, you would have to use the macro BOOST_TTI_HAS_MEMBER_FUNCTION. Here is how you could use it:

#include <boost/tti/has_member_function.hpp>

// Generate the metafunction
BOOST_TTI_HAS_MEMBER_FUNCTION(toString)

// Check whether T has a member function toString
// which takes no parameter and returns a std::string
constexpr bool foo = has_member_function_toString<T, std::string>::value;

Then, you could use the bool to create a SFINAE check.

Explanation

The macro BOOST_TTI_HAS_MEMBER_FUNCTION generates the metafunction has_member_function_toString which takes the checked type as its first template parameter. The second template parameter corresponds to the return type of the member function, and the following parameters correspond to the types of the function's parameters. The member value contains true if the class T has a member function std::string toString().

Alternatively, has_member_function_toString can take a member function pointer as a template parameter. Therefore, it is possible to replace has_member_function_toString<T, std::string>::value by has_member_function_toString<std::string T::* ()>::value.

Medici answered 25/2, 2014 at 12:52 Comment(11)
more concise than 03Fulgurite
@Fulgurite I think that Boost.TTI works with C++03 too, but it's the least elegant solution of the lot.Medici
Is the C++20 solution really valid? I would like it - but it is refused by g++ and msvc - only accepted by clang.Sternson
at cppreference you can read: If a requires-expression contains invalid types or expressions in its requirements, and it does not appear within the declaration of a templated entity, then the program is ill-formed.Sternson
@BerndBaumanns Really? I got it to work with GCC trunk: godbolt.org/z/CBwZdE Maybe you're right, I only checked that it worked but didn't check whether it was legal according to the standard wording.Medici
I tested it not with gcc trunk - just with version 9.2 which does not like it (see: godbolt.org/z/_5pr_t). It would be really nice! But your are right - with g++ trunk it is just translated into a boolean value - but is it guaranteed by the standard?Sternson
But it is still rejected by the newest version of the MSVC compiler with concepts support (which is not available at godbolt)Sternson
I know that there was a proposal (or a DR) that made requires expressions globally usable as boolean expressions, but it's orthogonal to your original comment about the program being ill-formed - I don't know enough about the wording to tell what is valid. GCC 9 only implemented the Concepts TS with -fconcepts so it's not surprising that it doesn't accept the requires as a boolean expression since it wasn't allowed in TS. If you're right and the code is incorrect then I will change it to use a concept, two overloads and requires.Medici
I like the detection toolkit solution (many have access to it under std::experimental), but I think it can be improved by using an integral_constant to enforce strict signature checking. template<class T> using toString_t = std::integral_constant<std::string(T::*)(), &T::toString>Forked
I can't suggest an edit because the "suggested edit queue is full", but the C++20 version should be modified according to @Morwenn's comment above. Solution should use a concept with two function overloads.Merchandising
@JamesMart That would indeed be the cleanest solution, but I wanted to stay true to the original code, showing that requires expression are the simple mechanism to achieve that. Correct API design is a different topic :pMedici
P
173

C++ allows SFINAE to be used for this (notice that with C++11 features this is simplier because it supports extended SFINAE on nearly arbitrary expressions - the below was crafted to work with common C++03 compilers):

#define HAS_MEM_FUNC(func, name)                                        \
    template<typename T, typename Sign>                                 \
    struct name {                                                       \
        typedef char yes[1];                                            \
        typedef char no [2];                                            \
        template <typename U, U> struct type_check;                     \
        template <typename _1> static yes &chk(type_check<Sign, &_1::func > *); \
        template <typename   > static no  &chk(...);                    \
        static bool const value = sizeof(chk<T>(0)) == sizeof(yes);     \
    }

The above template and macro tries to instantiate a template, giving it a member function pointer type, and the actual member function pointer. If the types do not fit, SFINAE causes the template to be ignored. Usage like this:

HAS_MEM_FUNC(toString, has_to_string);

template<typename T> void
doSomething() {
   if(has_to_string<T, std::string(T::*)()>::value) {
      ...
   } else {
      ...
   }
}

But note that you cannot just call that toString function in that if branch. Since the compiler will check for validity in both branches, that would fail for cases the function doesn't exist. One way is to use SFINAE once again (enable_if can be obtained from boost, too):

template<bool C, typename T = void>
struct enable_if {
  typedef T type;
};

template<typename T>
struct enable_if<false, T> { };

HAS_MEM_FUNC(toString, has_to_string);

template<typename T> 
typename enable_if<has_to_string<T, 
                   std::string(T::*)()>::value, std::string>::type
doSomething(T * t) {
   /* something when T has toString ... */
   return t->toString();
}

template<typename T> 
typename enable_if<!has_to_string<T, 
                   std::string(T::*)()>::value, std::string>::type
doSomething(T * t) {
   /* something when T doesnt have toString ... */
   return "T::toString() does not exist.";
}

Have fun using it. The advantage of it is that it also works for overloaded member functions, and also for const member functions (remember using std::string(T::*)() const as the member function pointer type then!).

Pouched answered 5/11, 2008 at 1:8 Comment(19)
what is the chk used in the macro?Cautery
@Cautery it's an overloaded function, where the first overload returns a ref to char array of size 1, and the other of size 2. Using SFINAE the one is masked out.Pouched
I like how type_check is used to ensure that the signatures agree exactly. Is there a way to make it so that it will match any method which could be called in the manner that a method with signature Sign could be called? (E.g. if Sign = std::string(T::*)(), allow std::string T::toString(int default = 42, ...) to match.)Ecclesiastic
I just figures something out about this that wasn't immediate obvious to me, so in case it helps others: chk isn't and needn't be defined! The sizeof operator determines the size of the output of chk without chk ever needing to be called.Scotney
I like this, but it gives an error if T is a void*, is there a way to bypass that? (I think it may be all basic types, but just being able to have a special case for void* would be enough for me)Armoire
@deek0146: Yes, T must not be a primitive type, because the pointer-to-method-of-T declaration is not subject to SFINAE and will error out for any non-class T. IMO the easiest solution is to combine with is_class check from boost.Tito
How can I make this work if my toString is a templated function?Citreous
@frank there is much you can check about a function template. What are you interested in?Pouched
Is this (or anything equivalent) in Boost?Anaplastic
This is brilliant! May I know why the return type is yes & and no & and not yes and no? ThanksJaneyjangle
@Viet: Because you can't return an array in C or C++. (An alternative to using a reference is to return a structure containing an array, you see this in other answers)Firer
I editted the post, to make it work with HAS_MEM_FUNC(operator -,someFuncName). Guess that one tiny space does matter :)Snowcap
@PawełStawarz on what compiler does this fail? I thought that you only get -> if you said func ## > ?Pouched
@JohannesSchaub-litb Visual Studio 2k8, tested it just now with HAS_MEM_FUNC(operator -,hasSub)Snowcap
@PawełStawarz wow that's weird. What about coliru.stacked-crooked.com/a/d686eb1c15df6740 ?Pouched
@JohannesSchaub-litb that compiles fine.Snowcap
@PawełStawarz I think you might be hitting a bug in 2k8 then. Clang agrees with GCC that it is ill-formed. I will keep the answer with your edit though, since now it works for one more compiler =)Pouched
@JohannesSchaub-litb maybe I am hitting some bug. 2k8 has plenty of those on board :) Still - keeping the change can only help people stuck on VS2k8. If you want - you can revert the change tho. I just thought it'll be usefull. To bot: my pleasure :)Snowcap
For some reason, in gcc type_check<Sign, &_1::func > doesn't work in stable way (only a first signature match is accepted if there are several methods with same sinature), but type_check<Sign, &_1::func > works?Instil
F
60

Though this question is two years old, I'll dare to add my answer. Hopefully it will clarify the previous, indisputably excellent, solution. I took the very helpful answers of Nicola Bonelli and Johannes Schaub and merged them into a solution that is, IMHO, more readable, clear and does not require the typeof extension:

template <class Type>
class TypeHasToString
{
    // This type won't compile if the second template parameter isn't of type T,
    // so I can put a function pointer type in the first parameter and the function
    // itself in the second thus checking that the function has a specific signature.
    template <typename T, T> struct TypeCheck;

    typedef char Yes;
    typedef long No;

    // A helper struct to hold the declaration of the function pointer.
    // Change it if the function signature changes.
    template <typename T> struct ToString
    {
        typedef void (T::*fptr)();
    };

    template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
    template <typename T> static No  HasToString(...);

public:
    static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));
};

I checked it with gcc 4.1.2. The credit goes mainly to Nicola Bonelli and Johannes Schaub, so give them a vote up if my answer helps you :)

Firn answered 2/9, 2010 at 12:50 Comment(3)
Just wondering, does this do anything that Konrad Rudolph's solution below does not do?Gliadin
@AlastairIrvine, this solution hides all the logic inside, Konrad's puts some of the burden on the user. Although short and much more readable, Konrad's solution requires a separate template specialization for each class that has toString. If you write a generic library, that wishes to work with any class out there (think of something like boost), then requiring the user to define additional specializations of some obscure templates might be unacceptable. Sometimes it's preferable to write a very complicated code to keep the public interface as simple as it can be.Firn
You should explain the reason for nesting the function-pointer type in the ToString class template. IIUC, it's to avoid instantiation errors when Type is not a class, right?Dann
W
37

A simple solution for C++11:

template<class T>
auto optionalToString(T* obj)
 -> decltype(  obj->toString()  )
{
    return     obj->toString();
}
auto optionalToString(...) -> string
{
    return "toString not defined";
}

Update, 3 years later: (and this is untested). To test for the existence, I think this will work:

template<class T>
constexpr auto test_has_toString_method(T* obj)
 -> decltype(  obj->toString() , std::true_type{} )
{
    return     obj->toString();
}
constexpr auto test_has_toString_method(...) -> std::false_type
{
    return "toString not defined";
}
Wilek answered 6/8, 2015 at 15:41 Comment(4)
This is simple and elegant, but strictly speaking does not answer OP's question: you don't enable the caller to check for a function's existence, you always provide it. But nice anyway.Memorialist
@AdrianW, good point. I've updated my answer. I haven't tested it thoughWilek
In case it helps someone else, I couldn't make this work without template<typename> before the variadic overload: it was not getting considered for resolution.Justen
Again, this is invalid C++11.Proven
U
36

Well, this question has a long list of answers already, but I would like to emphasize the comment from Morwenn: there is a proposal for C++17 that makes it really much simpler. See N4502 for details, but as a self-contained example consider the following.

This part is the constant part, put it in a header.

// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf.
template <typename...>
using void_t = void;

// Primary template handles all types not supporting the operation.
template <typename, template <typename> class, typename = void_t<>>
struct detect : std::false_type {};

// Specialization recognizes/validates only types supporting the archetype.
template <typename T, template <typename> class Op>
struct detect<T, Op, void_t<Op<T>>> : std::true_type {};

then there is the variable part, where you specify what you are looking for (a type, a member type, a function, a member function etc.). In the case of the OP:

template <typename T>
using toString_t = decltype(std::declval<T>().toString());

template <typename T>
using has_toString = detect<T, toString_t>;

The following example, taken from N4502, shows a more elaborate probe:

// Archetypal expression for assignment operation.
template <typename T>
using assign_t = decltype(std::declval<T&>() = std::declval<T const &>())

// Trait corresponding to that archetype.
template <typename T>
using is_assignable = detect<T, assign_t>;

Compared to the other implementations described above, this one is fairly simple: a reduced set of tools (void_t and detect) suffices, no need for hairy macros. Besides, it was reported (see N4502) that it is measurably more efficient (compile-time and compiler memory consumption) than previous approaches.

Here is a live example. It works fine with Clang, but unfortunately, GCC versions before 5.1 followed a different interpretation of the C++11 standard which caused void_t to not work as expected. Yakk already provided the work-around: use the following definition of void_t (void_t in parameter list works but not as return type):

#if __GNUC__ < 5 && ! defined __clang__
// https://mcmap.net/q/24115/-void_t-in-parameter-list-works-but-not-as-return-type
template <typename...>
struct voider
{
  using type = void;
};
template <typename...Ts>
using void_t = typename voider<Ts...>::type;
#else
template <typename...>
using void_t = void;
#endif
Urson answered 15/6, 2015 at 14:43 Comment(3)
Is it possible to extend it to detect non-member functions?Clements
Yes, sure. Look carefully at the examples: you basically provide an expression and check whether it's valid. Nothing requires this expression to be only about a member function call.Urson
N4502 (open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf) is the way of the future... I was looking for a neat way of detecting things on types and N4502 is the way to go.Egmont
B
30

This is what type traits are there for. Unfortunately, they have to be defined manually. In your case, imagine the following:

template <typename T>
struct response_trait {
    static bool const has_tostring = false;
};

template <>
struct response_trait<your_type_with_tostring> {
    static bool const has_tostring = true;
}
Bently answered 2/11, 2008 at 20:26 Comment(14)
you should prefer enum for traits instead of static constants : " Static constant members are lvalues,which forces the compiler to instantiate and allocate the definition for the static member. As a result, the computation is no longer limited to a pure "compile-time" effect."Bovid
"Enumeration values aren't lvalues(that is,they don't have an address).So, when you pass them "by reference," no static memory is used. It's almost exactly as if you passed the computed value as a literal. These considerations motivate us to use enumeration values" C++ Templates:The Complete GuideBovid
Comptrol: no, the cited passage doesn't apply here since integer type static constants are a special case! They behave exactly like an enum here and are the preferred way. The old enum hack was only necessary on compilers that didn't follow the C++ standard.Bently
@Konrad: Unfortunately, that's not the case. "The member shall still be defined in a namespace scope if it is used in the program .." [C++03 9.4.2/4]Pisciculture
@Roger Pate: Not quite. “used in the program” here is apparently synonymous with “referenced”. The prevailing reading of this passage, and the one implemented by all modern C++ compilers, is that you can take the value of a static constant without needing to declare it (the previous sentence says this: “… the member can appear in integral constant expressions …”). You only need to define it if you take its address (explicitly via &T::x or implicitly by binding it to a reference).Bently
@Roger Pate: Furthermore, this usage (explicitly without a definition) is common practice in eminent C++ libraries, e.g. in several Boost libraries (Boost.MPL, to name just one).Bently
"used" refers to the definition of "used" in the one definition rule. The 1 ? a : a expression uses a for example.Pouched
@Johannes Schaub - litb: Interesting – so this means that Boost is strictly speaking not standard conforming? Will the proposed resolution be part of the next standard? Under the explanation of “review” it says that the working group has reached an informal consensus.Bently
@Konrad boost seems to provide out of line definitions. A quick test shows that &boost::mpl::int_<0>::value compiles fine.Pouched
@Johannes Schaub - litb: It doesn’t, in general. int_::value seems to be an exception if it compiles. Others definitely don’t provide definitions. Some libraries seem to use a compile-time flag BOOST_NO_INCLASS_MEMBER_INITIALIZATION for the decision.Bently
@Konrad, in-class initializations don't preclude an out-of-class definition. So that macro just seems to say that it won't or will initialize in class, but it doesn't seem to say something about an out-of-class definition being provided. The link points to a test, probably they already knew that they don't access the object properties of the constants and thus didn't provide definitions. But i certainly won't say that all of boost is conformant, there surely are nonconformant bits hidden somewhere ^^Pouched
@Johannes Schaub - litb: “in-class initializations don't preclude an out-of-class definition” I know but the macro was used in precisely the context of out-of class definitions (with initialization being inline) in some file. The name poorly reflects that, granted.Bently
How do you use this? How can you make conditional compilation check the value of the boolean has_tostring?Acquaintance
Here is an example of how to use type traits for conditional compilation in C++11Acquaintance
D
19

Yet another way to do it in C++17 (inspired by boost:hana).

This solution does not require has_something<T> SFINAE type traits classes.

Solution

/// @file has_something.h
/// The `has_member` macro implementation

#pragma once

#include <type_traits>

template<typename T, typename F>
constexpr auto has_member_impl(F&& f) -> decltype(f(std::declval<T>()), true)
{
  return true;
}

template<typename>
constexpr bool has_member_impl(...) { return false; }

#define has_member(T, EXPR) \
 has_member_impl<T>( [](auto&& obj)->decltype(obj.EXPR){} )

Test

/// @file test.cpp

#include "has_something.h"

#include <iostream>
#include <string>

struct Example {
    int Foo;
    void Bar() {}
    std::string toString() { return "Hello from Example::toString()!"; }
};

struct Example2 {
    int X;
};

template<class T>
std::string optionalToString(T* obj)
{
    if constexpr(has_member(T, toString()))
        return obj->toString();
    else
        return "toString not defined";
}

int main() {
    static_assert(has_member(Example, Foo), 
                  "Example class must have Foo member");
    static_assert(has_member(Example, Bar()), 
                  "Example class must have Bar() member function");
    static_assert(!has_member(Example, ZFoo), 
                  "Example class must not have ZFoo member.");
    static_assert(!has_member(Example, ZBar()), 
                  "Example class must not have ZBar() member function");

    Example e1;
    Example2 e2;

    std::cout << "e1: " << optionalToString(&e1) << "\n";
    std::cout << "e1: " << optionalToString(&e2) << "\n";
}
Dendriform answered 9/6, 2020 at 21:37 Comment(5)
Is it possible to detect a private member?Intuition
@Intuition It depends on where do you use has_member macro. If you use it inside the class to check the private member existence, then yes, it does work. If you use that macro outside of class, for example in some function, then macro does not work. But, if you add this function to the friend list, then it works.Dendriform
The best option I tried from this question's answers: min amount of code that works not only with members but with free function as well. I have wrote generic toString that check all possible ways in my project to convert value to string. Best answer.Bursitis
This is in my opinion the best option for pre-C++20. By the way, does it require C++17? Isn't C++14 with variadic lambdas enough?Exorcism
@Exorcism That solution requires constexpr lambda which is introduced in C++17Dendriform
E
17

Here is the most concise way I found in C++20, which is very close from your question:

template<class T>
std::string optionalToString(T* obj)
{
  if constexpr (requires { obj->toString(); })
    return obj->toString();
  else
    return "toString not defined";
}

See it live on godbolt: https://gcc.godbolt.org/z/5jb1d93Ms

Ellipsis answered 11/6, 2021 at 19:33 Comment(1)
Language keeps getting better! I far prefer this to any SFINAE mess or convoluted macro expansions..Narcosis
T
14

This is a C++11 solution for the general problem if "If I did X, would it compile?"

template<class> struct type_sink { typedef void type; }; // consumes a type, and makes it `void`
template<class T> using type_sink_t = typename type_sink<T>::type;
template<class T, class=void> struct has_to_string : std::false_type {}; \
template<class T> struct has_to_string<
  T,
  type_sink_t< decltype( std::declval<T>().toString() ) >
>: std::true_type {};

Trait has_to_string such that has_to_string<T>::value is true if and only if T has a method .toString that can be invoked with 0 arguments in this context.

Next, I'd use tag dispatching:

namespace details {
  template<class T>
  std::string optionalToString_helper(T* obj, std::true_type /*has_to_string*/) {
    return obj->toString();
  }
  template<class T>
  std::string optionalToString_helper(T* obj, std::false_type /*has_to_string*/) {
    return "toString not defined";
  }
}
template<class T>
std::string optionalToString(T* obj) {
  return details::optionalToString_helper( obj, has_to_string<T>{} );
}

which tends to be more maintainable than complex SFINAE expressions.

You can write these traits with a macro if you find yourself doing it alot, but they are relatively simple (a few lines each) so maybe not worth it:

#define MAKE_CODE_TRAIT( TRAIT_NAME, ... ) \
template<class T, class=void> struct TRAIT_NAME : std::false_type {}; \
template<class T> struct TRAIT_NAME< T, type_sink_t< decltype( __VA_ARGS__ ) > >: std::true_type {};

what the above does is create a macro MAKE_CODE_TRAIT. You pass it the name of the trait you want, and some code that can test the type T. Thus:

MAKE_CODE_TRAIT( has_to_string, std::declval<T>().toString() )

creates the above traits class.

As an aside, the above technique is part of what MS calls "expression SFINAE", and their 2013 compiler fails pretty hard.

Note that in C++1y the following syntax is possible:

template<class T>
std::string optionalToString(T* obj) {
  return compiled_if< has_to_string >(*obj, [&](auto&& obj) {
    return obj.toString();
  }) *compiled_else ([&]{ 
    return "toString not defined";
  });
}

which is an inline compilation conditional branch that abuses lots of C++ features. Doing so is probably not worth it, as the benefit (of code being inline) is not worth the cost (of next to nobody understanding how it works), but the existence of that above solution may be of interest.

Tortuga answered 2/6, 2014 at 13:58 Comment(5)
Does this handle private cases?Estreat
@Estreat I would have to experiment: how templates interact with private/public/protected is a bit obscure to me. It will not matter where you invoke has_to_string however.Tortuga
but you know, if look from the other side... We can reach protected members from the Derived class. Maybe if put all this stuff INSIDE class, and convert from structs to constexpr functions...Estreat
Here, look at this coliru.stacked-crooked.com/a/ee94d16e7c07e093 I just can't make it constexprEstreat
@Estreat C++1y makes it work: coliru.stacked-crooked.com/a/d8cdfff24a171394Tortuga
N
10

Here are some usage snippets: *The guts for all this are farther down

Check for member x in a given class. Could be var, func, class, union, or enum:

CREATE_MEMBER_CHECK(x);
bool has_x = has_member_x<class_to_check_for_x>::value;

Check for member function void x():

//Func signature MUST have T as template variable here... simpler this way :\
CREATE_MEMBER_FUNC_SIG_CHECK(x, void (T::*)(), void__x);
bool has_func_sig_void__x = has_member_func_void__x<class_to_check_for_x>::value;

Check for member variable x:

CREATE_MEMBER_VAR_CHECK(x);
bool has_var_x = has_member_var_x<class_to_check_for_x>::value;

Check for member class x:

CREATE_MEMBER_CLASS_CHECK(x);
bool has_class_x = has_member_class_x<class_to_check_for_x>::value;

Check for member union x:

CREATE_MEMBER_UNION_CHECK(x);
bool has_union_x = has_member_union_x<class_to_check_for_x>::value;

Check for member enum x:

CREATE_MEMBER_ENUM_CHECK(x);
bool has_enum_x = has_member_enum_x<class_to_check_for_x>::value;

Check for any member function x regardless of signature:

CREATE_MEMBER_CHECK(x);
CREATE_MEMBER_VAR_CHECK(x);
CREATE_MEMBER_CLASS_CHECK(x);
CREATE_MEMBER_UNION_CHECK(x);
CREATE_MEMBER_ENUM_CHECK(x);
CREATE_MEMBER_FUNC_CHECK(x);
bool has_any_func_x = has_member_func_x<class_to_check_for_x>::value;

OR

CREATE_MEMBER_CHECKS(x);  //Just stamps out the same macro calls as above.
bool has_any_func_x = has_member_func_x<class_to_check_for_x>::value;

Details and core:

/*
    - Multiple inheritance forces ambiguity of member names.
    - SFINAE is used to make aliases to member names.
    - Expression SFINAE is used in just one generic has_member that can accept
      any alias we pass it.
*/

//Variadic to force ambiguity of class members.  C++11 and up.
template <typename... Args> struct ambiguate : public Args... {};

//Non-variadic version of the line above.
//template <typename A, typename B> struct ambiguate : public A, public B {};

template<typename A, typename = void>
struct got_type : std::false_type {};

template<typename A>
struct got_type<A> : std::true_type {
    typedef A type;
};

template<typename T, T>
struct sig_check : std::true_type {};

template<typename Alias, typename AmbiguitySeed>
struct has_member {
    template<typename C> static char ((&f(decltype(&C::value))))[1];
    template<typename C> static char ((&f(...)))[2];

    //Make sure the member name is consistently spelled the same.
    static_assert(
        (sizeof(f<AmbiguitySeed>(0)) == 1)
        , "Member name specified in AmbiguitySeed is different from member name specified in Alias, or wrong Alias/AmbiguitySeed has been specified."
    );

    static bool const value = sizeof(f<Alias>(0)) == 2;
};

Macros (El Diablo!):

CREATE_MEMBER_CHECK:

//Check for any member with given name, whether var, func, class, union, enum.
#define CREATE_MEMBER_CHECK(member)                                         \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct Alias_##member;                                                      \
                                                                            \
template<typename T>                                                        \
struct Alias_##member <                                                     \
    T, std::integral_constant<bool, got_type<decltype(&T::member)>::value>  \
> { static const decltype(&T::member) value; };                             \
                                                                            \
struct AmbiguitySeed_##member { char member; };                             \
                                                                            \
template<typename T>                                                        \
struct has_member_##member {                                                \
    static const bool value                                                 \
        = has_member<                                                       \
            Alias_##member<ambiguate<T, AmbiguitySeed_##member>>            \
            , Alias_##member<AmbiguitySeed_##member>                        \
        >::value                                                            \
    ;                                                                       \
}

CREATE_MEMBER_VAR_CHECK:

//Check for member variable with given name.
#define CREATE_MEMBER_VAR_CHECK(var_name)                                   \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct has_member_var_##var_name : std::false_type {};                      \
                                                                            \
template<typename T>                                                        \
struct has_member_var_##var_name<                                           \
    T                                                                       \
    , std::integral_constant<                                               \
        bool                                                                \
        , !std::is_member_function_pointer<decltype(&T::var_name)>::value   \
    >                                                                       \
> : std::true_type {}

CREATE_MEMBER_FUNC_SIG_CHECK:

//Check for member function with given name AND signature.
#define CREATE_MEMBER_FUNC_SIG_CHECK(func_name, func_sig, templ_postfix)    \
                                                                            \
template<typename T, typename = std::true_type>                             \
struct has_member_func_##templ_postfix : std::false_type {};                \
                                                                            \
template<typename T>                                                        \
struct has_member_func_##templ_postfix<                                     \
    T, std::integral_constant<                                              \
        bool                                                                \
        , sig_check<func_sig, &T::func_name>::value                         \
    >                                                                       \
> : std::true_type {}

CREATE_MEMBER_CLASS_CHECK:

//Check for member class with given name.
#define CREATE_MEMBER_CLASS_CHECK(class_name)               \
                                                            \
template<typename T, typename = std::true_type>             \
struct has_member_class_##class_name : std::false_type {};  \
                                                            \
template<typename T>                                        \
struct has_member_class_##class_name<                       \
    T                                                       \
    , std::integral_constant<                               \
        bool                                                \
        , std::is_class<                                    \
            typename got_type<typename T::class_name>::type \
        >::value                                            \
    >                                                       \
> : std::true_type {}

CREATE_MEMBER_UNION_CHECK:

//Check for member union with given name.
#define CREATE_MEMBER_UNION_CHECK(union_name)               \
                                                            \
template<typename T, typename = std::true_type>             \
struct has_member_union_##union_name : std::false_type {};  \
                                                            \
template<typename T>                                        \
struct has_member_union_##union_name<                       \
    T                                                       \
    , std::integral_constant<                               \
        bool                                                \
        , std::is_union<                                    \
            typename got_type<typename T::union_name>::type \
        >::value                                            \
    >                                                       \
> : std::true_type {}

CREATE_MEMBER_ENUM_CHECK:

//Check for member enum with given name.
#define CREATE_MEMBER_ENUM_CHECK(enum_name)                 \
                                                            \
template<typename T, typename = std::true_type>             \
struct has_member_enum_##enum_name : std::false_type {};    \
                                                            \
template<typename T>                                        \
struct has_member_enum_##enum_name<                         \
    T                                                       \
    , std::integral_constant<                               \
        bool                                                \
        , std::is_enum<                                     \
            typename got_type<typename T::enum_name>::type  \
        >::value                                            \
    >                                                       \
> : std::true_type {}

CREATE_MEMBER_FUNC_CHECK:

//Check for function with given name, any signature.
#define CREATE_MEMBER_FUNC_CHECK(func)          \
template<typename T>                            \
struct has_member_func_##func {                 \
    static const bool value                     \
        = has_member_##func<T>::value           \
        && !has_member_var_##func<T>::value     \
        && !has_member_class_##func<T>::value   \
        && !has_member_union_##func<T>::value   \
        && !has_member_enum_##func<T>::value    \
    ;                                           \
}

CREATE_MEMBER_CHECKS:

//Create all the checks for one member.  Does NOT include func sig checks.
#define CREATE_MEMBER_CHECKS(member)    \
CREATE_MEMBER_CHECK(member);            \
CREATE_MEMBER_VAR_CHECK(member);        \
CREATE_MEMBER_CLASS_CHECK(member);      \
CREATE_MEMBER_UNION_CHECK(member);      \
CREATE_MEMBER_ENUM_CHECK(member);       \
CREATE_MEMBER_FUNC_CHECK(member)
Nippon answered 12/6, 2011 at 21:40 Comment(3)
do you have any idea why if we change sig_check<func_sig, &T::func_name> to free function checking : sig_check<func_sig, &func_name> it fails to build with "undeclared identifier" mentioning the name of the function we want to check ? because I would expect SFINAE to make it NOT an error, it does just that for members, why not for free functions ?Kaiak
I assume it would have something to do with the fact that a free function isn't a class or struct. This technique of deducing the presence of a member really centers on the multiple inheritance mechanism in C++ forcing ambiguity between a stub class that only exists for the purpose of hosting the member you're checking for vs the class you're actually checking for the member in. That's an interesting question though, hadn't thought about it. You might check around for other C++11/14 member-check techniques, I've seen some clever things in the new standard.Nippon
Thanks for your answer, I think I might have to check more in depth that intel you give about inheritance, because until now I didn't see any correlation between simply relying on SFINAE to make an expression that wouldn't be correct expressing access to a member in a template type parameter, and multiple inheritance. But I completely believe that in C++ even distant concepts can bleed on each other. Now for free functions this question is interesting: stackoverflow.com/questions/26744589 T.C answer seems to use a trick of declaring a dummy to avoid the "undeclared identifier"Kaiak
S
10

With C++ 20 you can write the following:

template<typename T>
concept has_toString = requires(const T& t) {
    t.toString();
};

template<typename T>
std::string optionalToString(const T& obj)
{
    if constexpr (has_toString<T>)
        return obj.toString();
    else
        return "toString not defined";
}
Sternson answered 4/4, 2020 at 20:29 Comment(0)
S
8

I wrote an answer to this in another thread that (unlike the solutions above) also checks inherited member functions:

SFINAE to check for inherited member functions

Here are some example from that solution:

Example1:

We are checking for a member with the following signature: T::const_iterator begin() const

template<class T> struct has_const_begin
{
    typedef char (&Yes)[1];
    typedef char (&No)[2];

    template<class U> 
    static Yes test(U const * data, 
                    typename std::enable_if<std::is_same<
                             typename U::const_iterator, 
                             decltype(data->begin())
                    >::value>::type * = 0);
    static No test(...);
    static const bool value = sizeof(Yes) == sizeof(has_const_begin::test((typename std::remove_reference<T>::type*)0));
};

Please notice that it even checks the constness of the method, and works with primitive types, as well. (I mean has_const_begin<int>::value is false and doesn't cause a compile-time error.)

Example 2

Now we are looking for the signature: void foo(MyClass&, unsigned)

template<class T> struct has_foo
{
    typedef char (&Yes)[1];
    typedef char (&No)[2];

    template<class U>
    static Yes test(U * data, MyClass* arg1 = 0,
                    typename std::enable_if<std::is_void<
                             decltype(data->foo(*arg1, 1u))
                    >::value>::type * = 0);
    static No test(...);
    static const bool value = sizeof(Yes) == sizeof(has_foo::test((typename std::remove_reference<T>::type*)0));
};

Please notice that MyClass doesn't has to be default constructible or to satisfy any special concept. The technique works with template members, as well.

I am eagerly waiting opinions regarding this.

Spann answered 6/1, 2012 at 9:48 Comment(0)
G
7

Now this was a nice little puzzle - great question!

Here's an alternative to Nicola Bonelli's solution that does not rely on the non-standard typeof operator.

Unfortunately, it does not work on GCC (MinGW) 3.4.5 or Digital Mars 8.42n, but it does work on all versions of MSVC (including VC6) and on Comeau C++.

The longer comment block has the details on how it works (or is supposed to work). As it says, I'm not sure which behavior is standards compliant - I'd welcome commentary on that.


update - 7 Nov 2008:

It looks like while this code is syntactically correct, the behavior that MSVC and Comeau C++ show does not follow the standard (thanks to Leon Timmermans and litb for pointing me in the right direction). The C++03 standard says the following:

14.6.2 Dependent names [temp.dep]

Paragraph 3

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

So, it looks like that when MSVC or Comeau consider the toString() member function of T performing name lookup at the call site in doToString() when the template is instantiated, that is incorrect (even though it's actually the behavior I was looking for in this case).

The behavior of GCC and Digital Mars looks to be correct - in both cases the non-member toString() function is bound to the call.

Rats - I thought I might have found a clever solution, instead I uncovered a couple compiler bugs...


#include <iostream>
#include <string>

struct Hello
{
    std::string toString() {
        return "Hello";
    }
};

struct Generic {};


// the following namespace keeps the toString() method out of
//  most everything - except the other stuff in this
//  compilation unit

namespace {
    std::string toString()
    {
        return "toString not defined";
    }

    template <typename T>
    class optionalToStringImpl : public T
    {
    public:
        std::string doToString() {

            // in theory, the name lookup for this call to 
            //  toString() should find the toString() in 
            //  the base class T if one exists, but if one 
            //  doesn't exist in the base class, it'll 
            //  find the free toString() function in 
            //  the private namespace.
            //
            // This theory works for MSVC (all versions
            //  from VC6 to VC9) and Comeau C++, but
            //  does not work with MinGW 3.4.5 or 
            //  Digital Mars 8.42n
            //
            // I'm honestly not sure what the standard says 
            //  is the correct behavior here - it's sort 
            //  of like ADL (Argument Dependent Lookup - 
            //  also known as Koenig Lookup) but without
            //  arguments (except the implied "this" pointer)

            return toString();
        }
    };
}

template <typename T>
std::string optionalToString(T & obj)
{
    // ugly, hacky cast...
    optionalToStringImpl<T>* temp = reinterpret_cast<optionalToStringImpl<T>*>( &obj);

    return temp->doToString();
}



int
main(int argc, char *argv[])
{
    Hello helloObj;
    Generic genericObj;

    std::cout << optionalToString( helloObj) << std::endl;
    std::cout << optionalToString( genericObj) << std::endl;
    return 0;
}
Grad answered 4/11, 2008 at 8:37 Comment(7)
No, it's not standards compliant, though I think it will work in GCC if you turn on the -fpermissive option.Protoxylem
I know the comments don't give a lot of room, but could you point to information on why it's not standards compliant? (I'm not arguing - I'm curious)Grad
Mike B: the standard says in 3.10 p15: "If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined" and that list indeed doesn't include the case you do.Pouched
i'm not sure why it doesnt add another comment of me: your toString call is unqualified. so it will always call the free function and never the one in the base, since the baseclass is dependant on a template type parameter.Pouched
@litb: Thanks for the pointers. I don't think 3.10 applies here. The call to toString() inside of doToString() is not "accessing the stored value of an object through an lvalue". But your 2nd comment is correct. I'll update the answer.Grad
You don't know whether doToString is virtual in the base-class. If it is, then you access the v-table of the object.Pouched
hold on, i've got the explicit quote from the standard about this: 9.3.1/1: "If a nonstatic member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined." This was just luck, someone cited it, and told me where he has it from :)Pouched
S
7

The standard C++ solution presented here by litb will not work as expected if the method happens to be defined in a base class.

For a solution that handles this situation refer to :

In Russian : http://www.rsdn.ru/forum/message/2759773.1.aspx

English Translation by Roman.Perepelitsa : http://groups.google.com/group/comp.lang.c++.moderated/tree/browse_frm/thread/4f7c7a96f9afbe44/c95a7b4c645e449f?pli=1

It is insanely clever. However one issue with this solutiion is that gives compiler errors if the type being tested is one that cannot be used as a base class (e.g. primitive types)

In Visual Studio, I noticed that if working with method having no arguments, an extra pair of redundant ( ) needs to be inserted around the argments to deduce( ) in the sizeof expression.

Sway answered 2/2, 2009 at 8:35 Comment(1)
Hmm, having developed my own version using that posts ideas, i found the idea has some other drawbacks so i removed the code from my answer again. One is that all functions have to be public in the target type. So you cannot check for a "f" function in this: struct g { void f(); private: void f(int); }; because one of the functions is private (this is because the code does using g::f;, which makes it fail if any f is not accessible).Pouched
R
7

An example using SFINAE and template partial specialization, by writing a Has_foo concept check:

#include <type_traits>
struct A{};

struct B{ int foo(int a, int b);};

struct C{void foo(int a, int b);};

struct D{int foo();};

struct E: public B{};

// available in C++17 onwards as part of <type_traits>
template<typename...>
using void_t = void;

template<typename T, typename = void> struct Has_foo: std::false_type{};

template<typename T> 
struct Has_foo<T, void_t<
    std::enable_if_t<
        std::is_same<
            int, 
            decltype(std::declval<T>().foo((int)0, (int)0))
        >::value
    >
>>: std::true_type{};


static_assert(not Has_foo<A>::value, "A does not have a foo");
static_assert(Has_foo<B>::value, "B has a foo");
static_assert(not Has_foo<C>::value, "C has a foo with the wrong return. ");
static_assert(not Has_foo<D>::value, "D has a foo with the wrong arguments. ");
static_assert(Has_foo<E>::value, "E has a foo since it inherits from B");
Revival answered 22/1, 2018 at 15:1 Comment(1)
If we default the second typename with int then we can do Has_foo<T, decltype(std::declval<T>().foo(0, 0))> : std::true_type {}; (godbolt)Gadoid
M
6

MSVC has the __if_exists and __if_not_exists keywords (Doc). Together with the typeof-SFINAE approach of Nicola I could create a check for GCC and MSVC like the OP looked for.

Update: Source can be found Here

Mangan answered 26/1, 2011 at 21:45 Comment(0)
H
5

I modified the solution provided in https://mcmap.net/q/24101/-how-can-you-check-whether-a-templated-class-has-a-member-function to make it a bit more general. Also since it doesn't use any of the new C++11 features we can use it with old compilers and should also work with msvc. But the compilers should enable C99 to use this since it uses variadic macros.

The following macro can be used to check if a particular class has a particular typedef or not.

/** 
 * @class      : HAS_TYPEDEF
 * @brief      : This macro will be used to check if a class has a particular
 * typedef or not.
 * @param typedef_name : Name of Typedef
 * @param name  : Name of struct which is going to be run the test for
 * the given particular typedef specified in typedef_name
 */
#define HAS_TYPEDEF(typedef_name, name)                           \
   template <typename T>                                          \
   struct name {                                                  \
      typedef char yes[1];                                        \
      typedef char no[2];                                         \
      template <typename U>                                       \
      struct type_check;                                          \
      template <typename _1>                                      \
      static yes& chk(type_check<typename _1::typedef_name>*);    \
      template <typename>                                         \
      static no& chk(...);                                        \
      static bool const value = sizeof(chk<T>(0)) == sizeof(yes); \
   }

The following macro can be used to check if a particular class has a particular member function or not with any given number of arguments.

/** 
 * @class      : HAS_MEM_FUNC
 * @brief      : This macro will be used to check if a class has a particular
 * member function implemented in the public section or not. 
 * @param func : Name of Member Function
 * @param name : Name of struct which is going to be run the test for
 * the given particular member function name specified in func
 * @param return_type: Return type of the member function
 * @param ellipsis(...) : Since this is macro should provide test case for every
 * possible member function we use variadic macros to cover all possibilities
 */
#define HAS_MEM_FUNC(func, name, return_type, ...)                \
   template <typename T>                                          \
   struct name {                                                  \
      typedef return_type (T::*Sign)(__VA_ARGS__);                \
      typedef char yes[1];                                        \
      typedef char no[2];                                         \
      template <typename U, U>                                    \
      struct type_check;                                          \
      template <typename _1>                                      \
      static yes& chk(type_check<Sign, &_1::func>*);              \
      template <typename>                                         \
      static no& chk(...);                                        \
      static bool const value = sizeof(chk<T>(0)) == sizeof(yes); \
   }

We can use the above 2 macros to perform the checks for has_typedef and has_mem_func as:

class A {
public:
  typedef int check;
  void check_function() {}
};

class B {
public:
  void hello(int a, double b) {}
  void hello() {}
};

HAS_MEM_FUNC(check_function, has_check_function, void, void);
HAS_MEM_FUNC(hello, hello_check, void, int, double);
HAS_MEM_FUNC(hello, hello_void_check, void, void);
HAS_TYPEDEF(check, has_typedef_check);

int main() {
  std::cout << "Check Function A:" << has_check_function<A>::value << std::endl;
  std::cout << "Check Function B:" << has_check_function<B>::value << std::endl;
  std::cout << "Hello Function A:" << hello_check<A>::value << std::endl;
  std::cout << "Hello Function B:" << hello_check<B>::value << std::endl;
  std::cout << "Hello void Function A:" << hello_void_check<A>::value << std::endl;
  std::cout << "Hello void Function B:" << hello_void_check<B>::value << std::endl;
  std::cout << "Check Typedef A:" << has_typedef_check<A>::value << std::endl;
  std::cout << "Check Typedef B:" << has_typedef_check<B>::value << std::endl;
}
Homunculus answered 6/11, 2013 at 15:16 Comment(1)
You can improve this to support member functions with template arguments. Change template <typename T> to template <typename T, typename ... Args>, then you can use "Args..." in your macro elipsis to create a check struct with variadic template args. eg. Detect "void onNext(const T &)" method HAS_MEM_FUNC( onNext, has_memberfn_onNext, void, Args... ); ... template <typename V> struct Foo { void onNext(const V &); static_assert< has_memberfn_onNext<Foo<V>,const V &>::value, "API fail" ); };Mariquilla
A
5

I know that this question is years old, but I think it would useful for people like me to have a more complete updated answer that also works for const overloaded methods such as std::vector<>::begin.

Based on that answer and that answer from my follow up question, here's a more complete answer. Note that this will only work with C++11 and higher.

#include <iostream>
#include <vector>

class EmptyClass{};

template <typename T>
class has_begin
{
    private:
    has_begin() = delete;
    
    struct one { char x[1]; };
    struct two { char x[2]; };

    template <typename C> static one test( decltype(void(std::declval<C &>().begin())) * ) ;
    template <typename C> static two test(...);    

public:
    static constexpr bool value = sizeof(test<T>(0)) == sizeof(one);
};
    
int main(int argc, char *argv[])
{
    std::cout << std::boolalpha;
    std::cout << "vector<int>::begin() exists: " << has_begin<std::vector<int>>::value << std::endl;
    std::cout << "EmptyClass::begin() exists: " << has_begin<EmptyClass>::value << std::endl;
    return 0;
}

Or the shorter version:

#include <iostream>
#include <vector>

class EmptyClass{};

template <typename T, typename = void>
struct has_begin : std::false_type {};

template <typename T>
struct has_begin<T, decltype(void(std::declval<T &>().begin()))> : std::true_type {};

int main(int argc, char *argv[])
{
    std::cout << std::boolalpha;
    std::cout << "vector<int>::begin() exists: " << has_begin<std::vector<int>>::value << std::endl;
    std::cout << "EmptyClass exists: " << has_begin<EmptyClass>::value << std::endl;
}

Note that here a complete sample call must be provided. This means that if we tested for the resize method's existence then we would have put resize(0).

Deep magic explanation:

The first answer posted of this question used test( decltype(&C::helloworld) ); however this is problematic when the method it is testing is ambiguous due const overloading, thus making the substitution attempt fail.

To solve this ambiguity we use a void statement which can take any parameters because it is always translated into a noop and thus the ambiguity is nullified and the call is valid as long as the method exists:

has_begin<T, decltype(void(std::declval<T &>().begin()))>

Here's what's happening in order: We use std::declval<T &>() to create a callable value for which begin can then be called. After that the value of begin is passed as a parameter to a void statement. We then retrieve the type of that void expression using the builtin decltype so that it can be used as a template type argument. If begin doesn't exist then the substitution is invalid and as per SFINAE the other declaration is used instead.

Aplomb answered 10/9, 2020 at 5:26 Comment(1)
I'm trying to understand why we need the void(...) part. I would've thought that this would work: template <auto> using v_to_void = void; ... v_to_void<std::declval<T&>().begin()> (avoiding decltype). Any idea why it doesn't?Gadoid
E
4

Strange nobody suggested the following nice trick I saw once on this very site :

template <class T>
struct has_foo
{
    struct S { void foo(...); };
    struct derived : S, T {};

    template <typename V, V> struct W {};

    template <typename X>
    char (&test(W<void (X::*)(), &X::foo> *))[1];

    template <typename>
    char (&test(...))[2];

    static const bool value = sizeof(test<derived>(0)) == 1;
};

You have to make sure T is a class. It seems that ambiguity in the lookup of foo is a substitution failure. I made it work on gcc, not sure if it is standard though.

Editorial answered 23/6, 2010 at 13:56 Comment(0)
H
4

How about this solution?

#include <type_traits>

template <typename U, typename = void> struct hasToString : std::false_type { };

template <typename U>
struct hasToString<U,
  typename std::enable_if<bool(sizeof(&U::toString))>::type
> : std::true_type { };
Had answered 8/7, 2013 at 19:25 Comment(2)
Fails if toString is overloaded, as &U::toString is ambiguous.Tortuga
@Yakk I think a cast can fix this problem.Had
B
4

The generic template that can be used for checking if some "feature" is supported by the type:

#include <type_traits>

template <template <typename> class TypeChecker, typename Type>
struct is_supported
{
    // these structs are used to recognize which version
    // of the two functions was chosen during overload resolution
    struct supported {};
    struct not_supported {};

    // this overload of chk will be ignored by SFINAE principle
    // if TypeChecker<Type_> is invalid type
    template <typename Type_>
    static supported chk(typename std::decay<TypeChecker<Type_>>::type *);

    // ellipsis has the lowest conversion rank, so this overload will be
    // chosen during overload resolution only if the template overload above is ignored
    template <typename Type_>
    static not_supported chk(...);

    // if the template overload of chk is chosen during
    // overload resolution then the feature is supported
    // if the ellipses overload is chosen the the feature is not supported
    static constexpr bool value = std::is_same<decltype(chk<Type>(nullptr)),supported>::value;
};

The template that checks whether there is a method foo that is compatible with signature double(const char*)

// if T doesn't have foo method with the signature that allows to compile the bellow
// expression then instantiating this template is Substitution Failure (SF)
// which Is Not An Error (INAE) if this happens during overload resolution
template <typename T>
using has_foo = decltype(double(std::declval<T>().foo(std::declval<const char*>())));

Examples

// types that support has_foo
struct struct1 { double foo(const char*); };            // exact signature match
struct struct2 { int    foo(const std::string &str); }; // compatible signature
struct struct3 { float  foo(...); };                    // compatible ellipsis signature
struct struct4 { template <typename T>
                 int    foo(T t); };                    // compatible template signature

// types that do not support has_foo
struct struct5 { void        foo(const char*); }; // returns void
struct struct6 { std::string foo(const char*); }; // std::string can't be converted to double
struct struct7 { double      foo(      int *); }; // const char* can't be converted to int*
struct struct8 { double      bar(const char*); }; // there is no foo method

int main()
{
    std::cout << std::boolalpha;

    std::cout << is_supported<has_foo, int    >::value << std::endl; // false
    std::cout << is_supported<has_foo, double >::value << std::endl; // false

    std::cout << is_supported<has_foo, struct1>::value << std::endl; // true
    std::cout << is_supported<has_foo, struct2>::value << std::endl; // true
    std::cout << is_supported<has_foo, struct3>::value << std::endl; // true
    std::cout << is_supported<has_foo, struct4>::value << std::endl; // true

    std::cout << is_supported<has_foo, struct5>::value << std::endl; // false
    std::cout << is_supported<has_foo, struct6>::value << std::endl; // false
    std::cout << is_supported<has_foo, struct7>::value << std::endl; // false
    std::cout << is_supported<has_foo, struct8>::value << std::endl; // false

    return 0;
}

http://coliru.stacked-crooked.com/a/83c6a631ed42cea4

Bathypelagic answered 10/5, 2016 at 15:2 Comment(1)
Is there way to inline the has_foo into the template call of is_supported. What I would like is to call something like: std::cout << is_supported<magic.foo(), struct1>::value << std::endl;. The reason for this, I want to define a has_foo for each different function signature that I want to check before I can check for the function?Overbid
R
3

My take: to universally determine if something is callable without making verbose type traits for each and every one, or using experimental features, or long code:

template<typename Callable, typename... Args, typename = decltype(declval<Callable>()(declval<Args>()...))>
std::true_type isCallableImpl(Callable, Args...) { return {}; }

std::false_type isCallableImpl(...) { return {}; }

template<typename... Args, typename Callable>
constexpr bool isCallable(Callable callable) {
    return decltype(isCallableImpl(callable, declval<Args>()...)){};
}

Usage:

constexpr auto TO_STRING_TEST = [](auto in) -> decltype(in.toString()) { return {}; };
constexpr bool TO_STRING_WORKS = isCallable<T>(TO_STRING_TEST);
Reservation answered 28/8, 2020 at 8:17 Comment(0)
G
2

There are a lot of answers here, but I failed, to find a version, that performs real method resolution ordering, while not using any of the newer c++ features (only using c++98 features).
Note: This version is tested and working with vc++2013, g++ 5.2.0 and the onlline compiler.

So I came up with a version, that only uses sizeof():

template<typename T> T declval(void);

struct fake_void { };
template<typename T> T &operator,(T &,fake_void);
template<typename T> T const &operator,(T const &,fake_void);
template<typename T> T volatile &operator,(T volatile &,fake_void);
template<typename T> T const volatile &operator,(T const volatile &,fake_void);

struct yes { char v[1]; };
struct no  { char v[2]; };
template<bool> struct yes_no:yes{};
template<> struct yes_no<false>:no{};

template<typename T>
struct has_awesome_member {
 template<typename U> static yes_no<(sizeof((
   declval<U>().awesome_member(),fake_void()
  ))!=0)> check(int);
 template<typename> static no check(...);
 enum{value=sizeof(check<T>(0)) == sizeof(yes)};
};


struct foo { int awesome_member(void); };
struct bar { };
struct foo_void { void awesome_member(void); };
struct wrong_params { void awesome_member(int); };

static_assert(has_awesome_member<foo>::value,"");
static_assert(!has_awesome_member<bar>::value,"");
static_assert(has_awesome_member<foo_void>::value,"");
static_assert(!has_awesome_member<wrong_params>::value,"");

Live demo (with extended return type checking and vc++2010 workaround): http://cpp.sh/5b2vs

No source, as I came up with it myself.

When running the Live demo on the g++ compiler, please note that array sizes of 0 are allowed, meaning that the static_assert used will not trigger a compiler error, even when it fails.
A commonly used work-around is to replace the 'typedef' in the macro with 'extern'.

Geocentric answered 25/10, 2015 at 10:28 Comment(4)
Your static asserts do not work. You need to use array size -1 instead of 0 (try putting static_assert(false);). I was using this in connection with CRTP where I want to determine whether the derived class has a particular function--which turns out not to work, yet your asserts always passed. I lost some hair to that one.Jalap
I'm assuming you're using g++. Please note, that gcc/g++ have an extension that allows for zero-sized array (gcc.gnu.org/onlinedocs/gcc/Zero-Length.html)Geocentric
Could you possibly rewrite this so as not to overload operator, ? e.g. choose another operator? Also, avoid pollution of the namespace with anything other than has_awesome_member?Susysuter
I'm sorry, but it has to be operator , since this is the only operator that's implemented by the builtin void-type (you can write ((void)0, foo()), but any other operator like in ((void)0 + foo()) would always cause a compiler error and cannot be overridden), meaning that this is required for being able to dectect functions with a void return type. - As for namespace pollution: Sure you could just put everything (except for operator ,(), which has to remain visible as a global operator) into some namespace and adjust has_awesome_member to simply make use of that namespace.Geocentric
H
1

Here is my version that handles all possible member function overloads with arbitrary arity, including template member functions, possibly with default arguments. It distinguishes 3 mutually exclusive scenarios when making a member function call to some class type, with given arg types: (1) valid, or (2) ambiguous, or (3) non-viable. Example usage:

#include <string>
#include <vector>

HAS_MEM(bar)
HAS_MEM_FUN_CALL(bar)

struct test
{
   void bar(int);
   void bar(double);
   void bar(int,double);

   template < typename T >
   typename std::enable_if< not std::is_integral<T>::value >::type
   bar(const T&, int=0){}

   template < typename T >
   typename std::enable_if< std::is_integral<T>::value >::type
   bar(const std::vector<T>&, T*){}

   template < typename T >
   int bar(const std::string&, int){}
};

Now you can use it like this:

int main(int argc, const char * argv[])
{
   static_assert( has_mem_bar<test>::value , "");

   static_assert( has_valid_mem_fun_call_bar<test(char const*,long)>::value , "");
   static_assert( has_valid_mem_fun_call_bar<test(std::string&,long)>::value , "");

   static_assert( has_valid_mem_fun_call_bar<test(std::vector<int>, int*)>::value , "");
   static_assert( has_no_viable_mem_fun_call_bar<test(std::vector<double>, double*)>::value , "");

   static_assert( has_valid_mem_fun_call_bar<test(int)>::value , "");
   static_assert( std::is_same<void,result_of_mem_fun_call_bar<test(int)>::type>::value , "");

   static_assert( has_valid_mem_fun_call_bar<test(int,double)>::value , "");
   static_assert( not has_valid_mem_fun_call_bar<test(int,double,int)>::value , "");

   static_assert( not has_ambiguous_mem_fun_call_bar<test(double)>::value , "");
   static_assert( has_ambiguous_mem_fun_call_bar<test(unsigned)>::value , "");

   static_assert( has_viable_mem_fun_call_bar<test(unsigned)>::value , "");
   static_assert( has_viable_mem_fun_call_bar<test(int)>::value , "");

   static_assert( has_no_viable_mem_fun_call_bar<test(void)>::value , "");

   return 0;
}

Here is the code, written in c++11, however, you can easily port it (with minor tweaks) to non-c++11 that has typeof extensions (e.g. gcc). You can replace the HAS_MEM macro with your own.

#pragma once

#if __cplusplus >= 201103

#include <utility>
#include <type_traits>

#define HAS_MEM(mem)                                                                                     \
                                                                                                     \
template < typename T >                                                                               \
struct has_mem_##mem                                                                                  \
{                                                                                                     \
  struct yes {};                                                                                     \
  struct no  {};                                                                                     \
                                                                                                     \
  struct ambiguate_seed { char mem; };                                                               \
  template < typename U > struct ambiguate : U, ambiguate_seed {};                                   \
                                                                                                     \
  template < typename U, typename = decltype(&U::mem) > static constexpr no  test(int);              \
  template < typename                                 > static constexpr yes test(...);              \
                                                                                                     \
  static bool constexpr value = std::is_same<decltype(test< ambiguate<T> >(0)),yes>::value ;         \
  typedef std::integral_constant<bool,value>    type;                                                \
};


#define HAS_MEM_FUN_CALL(memfun)                                                                         \
                                                                                                     \
template < typename Signature >                                                                       \
struct has_valid_mem_fun_call_##memfun;                                                               \
                                                                                                     \
template < typename T, typename... Args >                                                             \
struct has_valid_mem_fun_call_##memfun< T(Args...) >                                                  \
{                                                                                                     \
  struct yes {};                                                                                     \
  struct no  {};                                                                                     \
                                                                                                     \
  template < typename U, bool = has_mem_##memfun<U>::value >                                         \
  struct impl                                                                                        \
  {                                                                                                  \
     template < typename V, typename = decltype(std::declval<V>().memfun(std::declval<Args>()...)) > \
     struct test_result { using type = yes; };                                                       \
                                                                                                     \
     template < typename V > static constexpr typename test_result<V>::type test(int);               \
     template < typename   > static constexpr                            no test(...);               \
                                                                                                     \
     static constexpr bool value = std::is_same<decltype(test<U>(0)),yes>::value;                    \
     using type = std::integral_constant<bool, value>;                                               \
  };                                                                                                 \
                                                                                                     \
  template < typename U >                                                                            \
  struct impl<U,false> : std::false_type {};                                                         \
                                                                                                     \
  static constexpr bool value = impl<T>::value;                                                      \
  using type = std::integral_constant<bool, value>;                                                  \
};                                                                                                    \
                                                                                                     \
template < typename Signature >                                                                       \
struct has_ambiguous_mem_fun_call_##memfun;                                                           \
                                                                                                     \
template < typename T, typename... Args >                                                             \
struct has_ambiguous_mem_fun_call_##memfun< T(Args...) >                                              \
{                                                                                                     \
  struct ambiguate_seed { void memfun(...); };                                                       \
                                                                                                     \
  template < class U, bool = has_mem_##memfun<U>::value >                                            \
  struct ambiguate : U, ambiguate_seed                                                               \
  {                                                                                                  \
    using ambiguate_seed::memfun;                                                                    \
    using U::memfun;                                                                                 \
  };                                                                                                 \
                                                                                                     \
  template < class U >                                                                               \
  struct ambiguate<U,false> : ambiguate_seed {};                                                     \
                                                                                                     \
  static constexpr bool value = not has_valid_mem_fun_call_##memfun< ambiguate<T>(Args...) >::value; \
  using type = std::integral_constant<bool, value>;                                                  \
};                                                                                                    \
                                                                                                     \
template < typename Signature >                                                                       \
struct has_viable_mem_fun_call_##memfun;                                                              \
                                                                                                     \
template < typename T, typename... Args >                                                             \
struct has_viable_mem_fun_call_##memfun< T(Args...) >                                                 \
{                                                                                                     \
  static constexpr bool value = has_valid_mem_fun_call_##memfun<T(Args...)>::value                   \
                             or has_ambiguous_mem_fun_call_##memfun<T(Args...)>::value;              \
  using type = std::integral_constant<bool, value>;                                                  \
};                                                                                                    \
                                                                                                     \
template < typename Signature >                                                                       \
struct has_no_viable_mem_fun_call_##memfun;                                                           \
                                                                                                     \
template < typename T, typename... Args >                                                             \
struct has_no_viable_mem_fun_call_##memfun < T(Args...) >                                             \
{                                                                                                     \
  static constexpr bool value = not has_viable_mem_fun_call_##memfun<T(Args...)>::value;             \
  using type = std::integral_constant<bool, value>;                                                  \
};                                                                                                    \
                                                                                                     \
template < typename Signature >                                                                       \
struct result_of_mem_fun_call_##memfun;                                                               \
                                                                                                     \
template < typename T, typename... Args >                                                             \
struct result_of_mem_fun_call_##memfun< T(Args...) >                                                  \
{                                                                                                     \
  using type = decltype(std::declval<T>().memfun(std::declval<Args>()...));                          \
};

#endif

Hujsak answered 11/1, 2014 at 13:54 Comment(0)
W
1

You can skip all the metaprogramming in C++14, and just write this using fit::conditional from the Fit library:

template<class T>
std::string optionalToString(T* x)
{
    return fit::conditional(
        [](auto* obj) -> decltype(obj->toString()) { return obj->toString(); },
        [](auto*) { return "toString not defined"; }
    )(x);
}

You can also create the function directly from the lambdas as well:

FIT_STATIC_LAMBDA_FUNCTION(optionalToString) = fit::conditional(
    [](auto* obj) -> decltype(obj->toString(), std::string()) { return obj->toString(); },
    [](auto*) -> std::string { return "toString not defined"; }
);

However, if you are using a compiler that doesn't support generic lambdas, you will have to write separate function objects:

struct withToString
{
    template<class T>
    auto operator()(T* obj) const -> decltype(obj->toString(), std::string())
    {
        return obj->toString();
    }
};

struct withoutToString
{
    template<class T>
    std::string operator()(T*) const
    {
        return "toString not defined";
    }
};

FIT_STATIC_FUNCTION(optionalToString) = fit::conditional(
    withToString(),
    withoutToString()
);
Wheen answered 14/1, 2016 at 23:43 Comment(1)
How easy is it to write this so as not to have to depend on fit or any library other than the standard?Susysuter
F
1

Probably not as good as other examples, but this is what I came up with for C++11. This works for picking overloaded methods.

template <typename... Args>
struct Pack {};

#define Proxy(T) ((T &)(*(int *)(nullptr)))

template <typename Class, typename ArgPack, typename = nullptr_t>
struct HasFoo
{
    enum { value = false };
};

template <typename Class, typename... Args>
struct HasFoo<
    Class,
    Pack<Args...>,
    decltype((void)(Proxy(Class).foo(Proxy(Args)...)), nullptr)>
{
    enum { value = true };
};

Example usage

struct Object
{
    int foo(int n)         { return n; }
#if SOME_CONDITION
    int foo(int n, char c) { return n + c; }
#endif
};

template <bool has_foo_int_char>
struct Dispatcher;

template <>
struct Dispatcher<false>
{
    template <typename Object>
    static int exec(Object &object, int n, char c)
    {
        return object.foo(n) + c;
    }
};

template <>
struct Dispatcher<true>
{
    template <typename Object>
    static int exec(Object &object, int n, char c)
    {
        return object.foo(n, c);
    }
};

int runExample()
{
    using Args = Pack<int, char>;
    enum { has_overload = HasFoo<Object, Args>::value };
    Object object;
    return Dispatcher<has_overload>::exec(object, 100, 'a');
}
Flabellum answered 21/11, 2020 at 16:33 Comment(0)
C
0

C++03 way

#define HasMember(NAME) \
  template<class Class, typename Type = void> \
  struct HasMember_##NAME \
  { \
    typedef char (&yes)[2]; \
    template<unsigned long> struct exists; \
    template<typename V> static yes Check (exists<sizeof(static_cast<Type>(&V::NAME))>*); \
    template<typename> static char Check (...); \
    static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes)); \
  }; \
  template<class Class> \
  struct HasMember_##NAME<Class, void> \
  { \
    typedef char (&yes)[2]; \
    template<unsigned long> struct exists; \
    template<typename V> static yes Check (exists<sizeof(&V::NAME)>*); \
    template<typename> static char Check (...); \
    static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes)); \
  }

Using above macro, you can find any member's existence in a class, be it variable or method. If there are 2 methods with same name, then we also have to provide the type of the method.

Usage:

#include<iostream>
struct S
{
  void Foo () const {}
//  void Foo () {}  // If uncommented then, SFINAE fails      
  int i;
};

HasMember(Foo);
HasMember(i);

int main ()
{
  std::cout << HasMember_Foo<S, void (S::*) () const>::value << "\n";
  std::cout << HasMember_Foo<S>::value << "\n";
  std::cout << HasMember_i<S, int (S::*)>::value << "\n";
  std::cout << HasMember_i<S>::value << "\n";
}

The 2nd cout may print 0 if there are 2 methods with same name Foo present in S. In case of member variable, the type (as mentioned in 3rd cout) is redundant as the variable name can be only 1. However to check the specific type, it's useful (for both method and variable).

Calpe answered 11/5, 2013 at 2:10 Comment(1)
This is now answered here in more organized way.Calpe
B
0

Here is an example of the working code.

template<typename T>
using toStringFn = decltype(std::declval<const T>().toString());

template <class T, toStringFn<T>* = nullptr>
std::string optionalToString(const T* obj, int)
{
    return obj->toString();
}

template <class T>
std::string optionalToString(const T* obj, long)
{
    return "toString not defined";
}

int main()
{
    A* a;
    B* b;

    std::cout << optionalToString(a, 0) << std::endl; // This is A
    std::cout << optionalToString(b, 0) << std::endl; // toString not defined
}

toStringFn<T>* = nullptr will enable the function which takes extra int argument which has a priority over function which takes long when called with 0.

You can use the same principle for the functions which returns true if function is implemented.

template <typename T>
constexpr bool toStringExists(long)
{
    return false;
}

template <typename T, toStringFn<T>* = nullptr>
constexpr bool toStringExists(int)
{
    return true;
}


int main()
{
    A* a;
    B* b;

    std::cout << toStringExists<A>(0) << std::endl; // true
    std::cout << toStringExists<B>(0) << std::endl; // false
}
Bondmaid answered 1/11, 2017 at 21:35 Comment(0)
D
0

I had a similar problem:

A template class that may be derived from few base classes, some that have a certain member and others that do not.

I solved it similarly to the "typeof" (Nicola Bonelli's) answer, but with decltype so it compiles and runs correctly on MSVS:

#include <iostream>
#include <string>

struct Generic {};    
struct HasMember 
{
  HasMember() : _a(1) {};
  int _a;
};    

// SFINAE test
template <typename T>
class S : public T
{
public:
  std::string foo (std::string b)
  {
    return foo2<T>(b,0);
  }

protected:
  template <typename T> std::string foo2 (std::string b, decltype (T::_a))
  {
    return b + std::to_string(T::_a);
  }
  template <typename T> std::string foo2 (std::string b, ...)
  {
    return b + "No";
  }
};

int main(int argc, char *argv[])
{
  S<HasMember> d1;
  S<Generic> d2;

  std::cout << d1.foo("HasMember: ") << std::endl;
  std::cout << d2.foo("Generic: ") << std::endl;
  return 0;
}
Dustproof answered 31/12, 2018 at 12:18 Comment(0)
H
0

I've been looking a method that allows to somehow to not tie structure name has_member to name of a class' member. Actually, this would be simpler if lambda can be allowed in unevaluated expression (this is forbidden by standard), i.e. has_member<ClassName, SOME_MACRO_WITH_DECLTYPE(member_name)>

#include <iostream>
#include <list>
#include <type_traits>

#define LAMBDA_FOR_MEMBER_NAME(NAME) [](auto object_instance) -> decltype(&(decltype(object_instance)::NAME)) {}

template<typename T>
struct TypeGetter
{
    constexpr TypeGetter() = default;
    constexpr TypeGetter(T) {}
    using type = T;

    constexpr auto getValue()
    {
        return std::declval<type>();
    }
};

template<typename T, typename LambdaExpressionT>
struct has_member {
    using lambda_prototype = LambdaExpressionT;

    //SFINAE
    template<class ValueT, class = void>
    struct is_void_t_deducable : std::false_type {};

    template<class ValueT>
    struct is_void_t_deducable<ValueT,
        std::void_t<decltype(std::declval<lambda_prototype>()(std::declval<ValueT>()))>> : std::true_type {};

    static constexpr bool value = is_void_t_deducable<T>::value;
};

struct SimpleClass
{
    int field;
    void method() {}
};

int main(void)
{   
    const auto helpful_lambda = LAMBDA_FOR_MEMBER_NAME(field);
    using member_field = decltype(helpful_lambda);
    std::cout << has_member<SimpleClass, member_field>::value;

    const auto lambda = LAMBDA_FOR_MEMBER_NAME(method);
    using member_method = decltype(lambda);
    std::cout << has_member<SimpleClass, member_method>::value;
    
}
Humus answered 13/2, 2021 at 21:54 Comment(0)
G
0

Pre-c++20, simple options for simple cases:

If you know your class is default constructible, we can make the syntax simpler.

We'll start with the simplest case: Default constructible and we know the expected return type. Example method:

int foo ();

We can write the type trait without declval:

template <auto v>
struct tag_v
{
    constexpr static auto value = v;
};

template <class, class = int>
struct has_foo_method : tag_v<false> {};

template <class T>
struct has_foo_method <T, decltype(T().foo())>
    : tag_v<true> {};

demo

Note that we set the default type to int because that's the return type of foo.

If there's multiple acceptable return types then we add a second argument to decltype that's the same type as the default, overriding the first argument:

decltype(T().foo(), int())

demo

(The int type here is unimportant - I use it because it's only 3 letters)

Gadoid answered 17/10, 2021 at 12:23 Comment(0)
B
-2
template<class T>
auto optionalToString(T* obj)
->decltype( obj->toString(), std::string() )
{
     return obj->toString();
}

template<class T>
auto optionalToString(T* obj)
->decltype( std::string() )
{
     throw "Error!";
}
Buck answered 25/2, 2019 at 13:16 Comment(1)
"We don't need no answer descriptions" ... please add some informative description to your answer to improve it. Thanks.Tyrannicide

© 2022 - 2024 — McMap. All rights reserved.