Ross Bencina
Ross Bencina

Reputation: 4173

How to store/retrieve member function pointers for use as template parameters?

For the purposes of metaprogramming, I would like to store a member function pointer in a type, and later use it to parameterise a template.

By analogy, here is a working example of how I can store an int in an integer_constant type:

template< int I >
struct integer_constant {
    static constexpr int value = I;  
};

template <int I>
struct A {
    // (client type, probably does other things with I)
    static constexpr int value = I;   
};

namespace {
    using cStored= integer_constant<42>; // store value
    static_assert(cStored::value == 42, "");

    // ...

    using aUseStored = A<cStored::value>; // use value as template parameter
    static_assert(aUseStored::value == 42, "");
}

Can I do the same thing with member function pointers? If not, why not?

struct S{
    void foo() {}
};

typedef void (S::*s_member_fn_type)();

template< s_member_fn_type M >
struct member_fn_constant {
    static constexpr s_member_fn_type value = M;  
};

template <s_member_fn_type M>
struct A {
    // (client type, probably does other things with M)
    static constexpr s_member_fn_type value = M;   
};

namespace {
    using cStored = member_fn_constant<&S::foo>; // store value

    // clang is ok with the following line
    // gcc 6.2: error: non-constant condition for static assertion
    // gcc 6.2: error: '(s_member_fn_type)member_fn_constant<&S::foo>::value' is not a constant expression
    static_assert(cStored::value == &S::foo, "");

    // following line gives:
    // clang 3.9.0 error: non-type template argument is not a pointer to member constant
    // gcc 6.2: error: could not convert template argument 'member_fn_constant<&S::foo>::value' to 'void (S::*)()'
    using aUseStored  = A<cStored::value>; // use value as template parameter
    //static_assert(aUseStored ::value == &S::foo, "");
}

I understand that I can add an extra level of indirection by passing the wrapper struct, instead of the function pointer, as follows:

template <typename MT>
struct B {
    static constexpr s_member_fn_type value = MT::value;   
};

namespace {
    using bUseStored  = B<cStored>;
}

But this does not help if my client class A is already defined to take a member function pointer.

Upvotes: 2

Views: 226

Answers (1)

Danh
Danh

Reputation: 6016

Pre-C++17, pointer to member function is not a constant expression.

From C++17, It's a constant expression as addressed by N4268.

clang has supported it with -std=c++1z from clang 3.5 as you can see C++ Support in Clang

g++ has claimed that it had supported it from g++ 6 but it seems not true, see C++ Standards Support in GCC

Upvotes: 3

Related Questions