You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++11下如何实现House类存储函数及参数以便后续调用?

解决House类的安全检查实现问题

嘿,我来帮你搞定这个House类的实现问题!先看看你的现有代码里的几个关键问题,再给你一个完全符合C++11标准的正确实现~

你的问题回顾

你有实现了LockCheck()方法的Door类,以及包含BurnerCheck()方法的Stove类,想要实现一个House类:

  • 构造函数能接收Door::LockCheck或Stove::BurnerCheck这类函数,以及对应任意数量的参数
  • 存储函数与参数,后续通过check_safety()调用执行

你给出的示例用法:

auto stove = Stove();
auto stove_check = stove.BurnerCheck;
auto burner_args = std::make_tuple<bool, bool>(true, false);
auto house = House(burner_args, stove_check);
// do some other stuff...
house.check_safety(); // 内部调用 stove.BurnerCheck(burner_args)

你的现有实现:

template <typename ReturnType, typename... Args>
class House {
public:
    House(Args... args, std::function<ReturnType(Args...)> func)
        : input_args_(std::forward_as_tuple(args...)), safety_func_(func) {}
};
private:
    Args... input_args_; // Is this the correct declaration?
    std::function<ReturnType(Args...)> safety_func_;
};

现有代码的问题

  1. 成员变量声明错误:模板参数包Args...不能直接作为成员变量类型,必须用std::tuple<Args...>来打包存储参数
  2. 构造函数参数顺序问题:C++11的模板推导对参数包位置有限制,把Args... args放在前面会导致编译器无法正确推导std::function的类型
  3. 成员函数处理缺失:你示例中传递的是类的非静态成员函数指针,这类指针必须绑定类实例才能调用(隐含this指针参数),现有代码没处理这个场景

符合C++11标准的正确实现

我们可以通过绑定可调用对象和参数,把它们转换成一个无参的函数对象存储,这样后续调用check_safety()会非常简洁。另外因为C++11没有std::apply,我们需要自己实现参数展开的辅助函数:

#include <functional>
#include <tuple>
#include <utility>

// C++11没有std::apply,自己实现tuple参数展开的辅助函数
template<typename Func, typename Tuple, size_t... Indices>
auto invoke_helper(Func&& func, Tuple&& tuple, std::index_sequence<Indices...>) 
    -> decltype(std::forward<Func>(func)(std::get<Indices>(std::forward<Tuple>(tuple))...)) {
    return std::forward<Func>(func)(std::get<Indices>(std::forward<Tuple>(tuple))...);
}

template<typename Func, typename Tuple>
auto invoke(Func&& func, Tuple&& tuple) 
    -> decltype(invoke_helper(std::forward<Func>(func), std::forward<Tuple>(tuple), 
                              std::make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>())) {
    using Indices = std::make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>;
    return invoke_helper(std::forward<Func>(func), std::forward<Tuple>(tuple), Indices());
}

// House类核心实现
template<typename Func, typename... Args>
class House {
public:
    // 构造函数:接收可调用对象和参数,绑定为无参函数
    House(Func&& func, Args&&... args) 
        : safety_check_(std::bind(
            [func = std::forward<Func>(func), args_tuple = std::make_tuple(std::forward<Args>(args)...)]() {
                invoke(func, args_tuple);
            }
        )) {}

    // 执行安全检查
    void check_safety() {
        safety_check_();
    }

private:
    std::function<void()> safety_check_;
};

// 辅助推导函数:C++11类模板无法自动推导参数,用这个函数简化对象创建
template<typename Func, typename... Args>
House<Func, Args...> make_house(Func&& func, Args&&... args) {
    return House<Func, Args...>(std::forward<Func>(func), std::forward<Args>(args)...);
}

// 测试用的Door和Stove类
class Door {
public:
    bool LockCheck(bool is_locked) {
        return is_locked;
    }
};

class Stove {
public:
    bool BurnerCheck(bool front_burner, bool back_burner) {
        return !front_burner && !back_burner;
    }
};

用法示例

方式1:先绑定成员函数与实例

int main() {
    Stove stove;
    // 用std::bind把Stove实例和成员函数绑定,得到可调用对象
    auto stove_check = std::bind(&Stove::BurnerCheck, &stove, std::placeholders::_1, std::placeholders::_2);
    // 用make_house创建House对象,传入绑定好的函数和参数
    auto house = make_house(stove_check, true, false);
    house.check_safety(); // 内部调用 stove.BurnerCheck(true, false)

    Door door;
    auto door_check = std::bind(&Door::LockCheck, &door, std::placeholders::_1);
    auto house2 = make_house(door_check, true);
    house2.check_safety(); // 内部调用 door.LockCheck(true)

    return 0;
}

方式2:直接传递成员函数、实例和参数(可选扩展)

如果不想手动写std::bind,可以给House类加一个重载构造函数:

// 在House类中添加针对成员函数的重载构造
template<typename Class, typename ReturnType, typename... MemArgs, typename... Args>
House(ReturnType (Class::*mem_func)(MemArgs...), Class* instance, Args&&... args)
    : safety_check_(std::bind(
        [mem_func, instance, args_tuple = std::make_tuple(std::forward<Args>(args)...)]() {
            invoke(std::bind(mem_func, instance), args_tuple);
        }
    )) {}

这样使用时更直接:

auto house = make_house(&Stove::BurnerCheck, &stove, true, false);
auto house2 = make_house(&Door::LockCheck, &door, true);

实现说明

  • 参数打包与展开:用std::tuple存储参数,通过自定义的invoke函数展开tuple元素作为函数参数
  • 可调用对象兼容:支持普通函数、成员函数指针、lambda等任意可调用类型
  • C++11兼容性:所有实现都基于C++11标准,没有使用后续版本的特性

内容的提问来源于stack exchange,提问作者BoltzmannBrain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:05:27