2

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?

tmaric
  • 5,347
  • 4
  • 42
  • 75
  • 1
    `is_member_function_pointer` classifies a *type,* i.e. it can be used to tell a `T(*)()` from a `T (C::*)()`. For introspection, you need heavier guns - something like what [Boost.TTI](http://www.boost.org/doc/libs/1_54_0/libs/tti/doc/html/the_type_traits_introspection_library/tti_detail_has_member_function.html) provides. – Angew is no longer proud of SO Feb 17 '14 at 11:20
  • @Angew: thanks for the Boost tip, but I don't understand what you mean by type classification. `is_member_function_pointer` provides a static boolean variable `value`, can't i just use that like I did above? – tmaric Feb 17 '14 at 11:23
  • 1
    Because the expression `&Type::boo` requires `Type` to have a `boo` member. You could use `is_member_function_pointer` to determine whether this `boo` is a member function or a data member. But it has to exist. The TTI library I linked to uses SFINAE to perform some level of compile-time introspection (actually determining *whether* a nested `boo` exists). – Angew is no longer proud of SO Feb 17 '14 at 11:46

1 Answers1

2

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.

Community
  • 1
  • 1
jrok
  • 54,456
  • 9
  • 109
  • 141