【问题标题】:Problems wrapping a const-member-function in a functor在仿函数中包装 const 成员函数的问题
【发布时间】:2021-03-22 19:09:14
【问题描述】:

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

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

错误消息本地化不是英文,但第一条消息是“不完整类型”。

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

在所示的 WrapP 中,我们可以在哪里以及如何表示 const 是可以接受的?是否可以定义一个同时接受 const 和 non-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;
}

【问题讨论】:

    标签: c++ variadic-templates template-argument-deduction


    【解决方案1】:

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

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

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

    【讨论】:

    • 一目了然(你向我展示了如何做到这一点!)。就是这样!添加超载后,一切都像魅力一样。非常感谢。
    • @MichaelB 没问题。次要点:正确的术语是“在添加 specialization 之后”,而不是 overload
    【解决方案2】:

    不要专门化 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时会比较麻烦。

    【讨论】:

    • 抱歉,boost 不是我们的选择。
    • @MichaelB:正如我告诉你的,你可以使用你自己的替代品。原理是一样的,CallableTraits 大多只是实现的样板。
    猜你喜欢
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 2011-06-04
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    相关资源
    最近更新 更多