在仿函数中包装常量成员函数的问题

Problems wrapping a const-member-function in a functor

我们实现了一个将回调传递给对象实例成员函数的系统。这很好用,请参见下面的代码。问题是当前的实现状态只处理非常量成员函数。

下面的代码编译并演示了系统正在运行。一旦包含 /* const */,它就不再编译。

错误消息已本地化,而非英语,但第一条消息是 'incomplete type'。

从逻辑上讲,对 const 成员函数的调用不应比对非 const 成员函数的调用更受限制,因此基本目标似乎是合理的。 很明显,const 成员的类型与非 const 成员的类型不同。问题是我们没有找到一种方法来向编译器表达该代码对 const 成员也有效。

在所示的 WrapP 中,我们可以在哪里以及如何表达 const 是可以接受的?是否可以定义一个同时接受常量和非常量成员函数的模板?

#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;
}

不要专门化 WrapP——而是继续将 auto F 作为您的模板参数,然后使用 Boost.CallableTraits 或您自己开发的解决方案提取您需要的信息:

template <auto F>
struct WrapP {
    using T = boost::callable_traits::class_of_t<decltype(F)>; 
    using R = boost::callable_traits::return_type_t<decltype(F)>; 

    T* obj_;

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

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

也可以提取 Args...,但是当您返回 std::tuple 时,它有点麻烦。

如果要将 WrapP 特化为 const 成员函数,您需要指定:

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

据我所知,没有办法在模板参数列表中允许 const 或非 const 成员函数指针,因此您我们必须为这些情况编写单独的专业化。