0

I was looking at answers of how to call a function only if it exists and found some code on this questiuon Is it possible to write a template to check for a function's existence?. I'm trying to use std::is_member_function_pointer as the discriminator to call specialised templated code. But I'm seeing true twice in the output, when I expect to see false and then true. Any suggestions on why this might be? The code can also be seen at https://ideone.com/HZ17Wf

#include <iostream>
#include <utility>
#include <type_traits>

namespace Ckb
{

struct Version
{
    enum { Major = 1, Minor = 0, Release = 0 };
    void CheckDependencies()
    {
        std::cout << "Ckb Check" << std::endl;
    }
};

}  // namespace Ckb

namespace Cg
{

struct Version { enum { Major = 1, Minor = 8, Release = 1 }; };

}  // namespace Cg

template <typename T, bool> struct RunCheck
{ void operator()() {std::cout << "false" << std::endl;} };

template <typename T> struct RunCheck<T, true>
{ void operator()() { std::cout << "true" << std::endl; } };

template <typename T> void Do()
{
    RunCheck<T, std::is_member_function_pointer<void(T::*)()>::value>()();
}

int main()
{
    Do<Cg::Version>();
    Do<Ckb::Version>();
    return 0;
}
Community
  • 1
  • 1
DSV
  • 1

1 Answers1

4

void(T::*)() is a member_function_pointer (even if T doesn't have any matching method).

I think you want to use something like:

#include <cstdint>

#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature)               \
    template <typename U>                                                   \
    class traitsName                                                        \
    {                                                                       \
    private:                                                                \
        template<typename T, T> struct helper;                              \
        template<typename T>                                                \
        static std::uint8_t check(helper<signature, &funcName>*);           \
        template<typename T> static std::uint16_t check(...);               \
    public:                                                                 \
        static                                                              \
        constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
    }

DEFINE_HAS_SIGNATURE(has_CheckDependencies, T::CheckDependencies, void (T::*)());

And then use it:

template <typename T> void Do()
{
    RunCheck<T, has_CheckDependencies<T>::value>()();
}
Jarod42
  • 173,454
  • 13
  • 146
  • 250
  • Thank you very much for the help, @Jarod42. That works well with a c++11 compiler. I've tried others and changing the types for short and int seems to work as well. Sadly, the target compiler I'm using is from the old Borland family (now Embarcadero) and version 4 does not compile. I think it has a problem with the line DEFINE_HAS_SIGNATURE(has_CheckDependencies, T::CheckDependencies, void (T::*)()) because for some weird reason it needs to know what T is. Mental... Anyway, thanks again for the help. – DSV May 29 '14 at 10:25