Search code examples
c++variadic-templatestemplate-argument-deduction

Problems wrapping a const-member-function in a functor


We implement a system that passes callbacks to object-instance member-functions. This works nicely, see the code below. The problem is that the current state of the implementation handles only non-const member functions.

The code below compiles and demonstrates that the system is working. As soon as the /* const */ is included, it no longer compiles.

The error messages are localized not English, but the first message is 'incomplete type'.

Logically, a call to a const member-function should be not more constrained than a call to a non-const member-function, so it seems that the basic goal is sensible. It is clear that the type of a const-member differs from that of a non-const member. The problem is that we do not find a way to express to the compiler that the code is also valid for const members.

Where and how in the shown WrapP can we express that a const is acceptable? Is it possible to define a single template that accepts both, const and non-const, member functions?

#include <algorithm>
#include <functional>
#include <iostream>

using std::cout;
using std::endl;

template <auto F>
struct WrapP;

template <typename T, typename R, typename ... Args, R(T::* F)(Args...)>
struct WrapP<F> {
    T* obj_;

    WrapP(T* instance) : obj_(instance) {}

    auto operator()(Args... args) const {
        return (obj_->*F)(args...);
    }
};

struct foo {
    // Const below is needed, but could not be activated.
    auto bar(double) /* const */ -> int { 
        return 314; };
};
int main() {
    foo x;
    // Create a functor for foo::bar
    WrapP<&foo::bar> fp{ &x };
    // Call the functor.
    std::cout << fp( 3.14159265  ) << std::endl;

    return 0;
}

Solution

  • If you want to specialize WrapP for a const member function, you need to specify that:

    template <typename T, typename R, typename ... Args, R(T::* F)(Args...) const>
    struct WrapP<F> {                                                   //  ^___^
     // ...
    };
    

    As far as I'm aware, there isn't a way to allow for either const or non-const member function pointers in a template parameter list, so you'll have to write separate specializations for those cases.