Question

I am trying to use is_member_function_pointer within an algorithm, to either call a specific member function of a type (if it exists), or do nothing at all:

template< class T >
struct is_member_function_pointer;

Checks whether T is a non-static member function pointer. Provides the member constant value which is equal to true, if T is a non-static member function pointer type. Otherwise, value is equal to false.

For example:

#include <iostream>
#include <type_traits>
#include <vector>

struct A
{
    void boo() const { std::cout << "boo." << std::endl; } 
};

struct B {};

template<bool> struct booable; 

template<>
struct booable<true> {

    template<typename Type>
    static void booIt(Type const & t)
    {
        t.boo(); 
    }
};

template<>
struct booable<false> {

    template<typename Type>
    static void booIt(Type const & t)
    {
        std::cout << "booing a non-booable type" << std::endl;
    }
};

template<typename Type>
void alg(Type const& t)
{
    booable<std::is_member_function_pointer<decltype(&Type::boo)>::value>::booIt(t); 
}

int main(int argc, const char *argv[])
{
    A a;  
    B b; 

    alg(a); 
    alg(b);

    return 0;
}

Struct A is booable and B is not. Within the algorithm alg, is_member_function_pointer boolean value is set to false or true depending on the fact if Type implements a member function boo. This boolean value is then used to specialize the booable struct, that implements booIt static member function, whose sole purpose is to either call boo on a booable object, or do nothing and inform the user.

However, compiling this (saved im main.cpp), results in a following compile-time error:

main.cpp: In instantiation of ‘void alg(const Type&) [with Type = B]’:
main.cpp:46:10:   required from here
main.cpp:37:54: error: ‘boo’ is not a member of ‘B’
booable<std::is_member_function_pointer<decltype(&Type::boo)>::value>::booIt(t);

Which makes me wonder: isn't reporting this as a useable boolean value and not a compile-time error the point of this trait structure? This is the same error I would get by simply doing

B b; 
b.boo(); 

What did I do wrong here?

Was it helpful?

Solution

Isn't reporting this as a useable boolean value and not a compile-time error the point of this trait structure?

Yes, but in order to test some member of a class, that member needs to exist.

You get the error because B doesn't have boo and instantiating alg results in decltype(&B::boo). You wouldn't expect decltype(&int::foo) to compile, would you?

What you need is a trait that check for existense of a member. See

for examples.

You can use the result of the check to specialize the template that does further test.

EDIT:

Here's a simple way to do check for boo using expression SFINAE:

template<typename T>
constexpr auto is_booable(int) -> decltype(std::declval<T>().boo(), bool())
{
    return true;
}

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

Usage:

booable< is_booable<Type>(0) >::booIt(t);

And Live example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top