【问题标题】:Template function accepting callable functors with X parameters模板函数接受带有 X 参数的可调用函子
【发布时间】:2013-05-11 10:44:12
【问题描述】:

我正在编写一个托管 C++ 程序,该程序运行用户编写的即时编译的 C 代码。从 C 代码中捕获并处理/忽略某些典型异常是绝对重要的。 为此,我从结构化异常处理块中调用 C 代码。由于这个块的性质和语义(以及它的调用位置),我已经将实际调用分离到它自己的函数:

    template <typename ret_type, class func>
        static ret_type Cstate::RunProtectedCode(func function) {
            ret_type ret = 0;
            __try {
                ret = function();
            }
            __except(ExceptionHandler(GetExceptionCode(), ExceptionStatus::CSubsystem)) {
                fprintf(stderr, "First chance exception in C-code.\n");
            }
            return ret;
        }

效果很好:

        RunProtectedCode<int>(entry);

但是是否有可能对它进行整形,以便我可以调用具有可变数量参数的函数-也许通过使用一些奇异的函子(显然唯一的要求是它不能有析构函数)?我正在使用 MSVC++ 2010。

【问题讨论】:

  • 有可变参数模板,但恐怕VS 2010不支持。
  • 不介意升级到VS2012,如果它可以在那里完成。可以做个代码示例吗?
  • 遗憾的是,VS2012 也不支持可变参数模板。
  • @Xeo,非常正确,但如果允许的话,现在还有 CTP。
  • @chris: 可惜 CTP 包含我们所说的 buggyadics :/

标签: c++ templates functor seh


【解决方案1】:

如果您可以使用 C++11,您可以使用可变模板来实现这一点。

template <typename ret_type, class func, typename... Args>
    static ret_type Cstate::RunProtectedCode(func function, Args&&... args) {
        ret_type ret = 0;
        __try {
            ret = function(std::forward<Args>(args)...);
        }
        __except(ExceptionHandler(GetExceptionCode(), ExceptionStatus::CSubsystem)) {
            fprintf(stderr, "First chance exception in C-code.\n");
        }
        return ret;
    }

你可以这样称呼它

RunProtectedCode<int>(entry2, 1, 2);
RunProtectedCode<int>(entry3, 1, "a", 3);

您可以改用 std::function 来简化它(一种)。

template <class func, typename... Args>
    static 
    typename func::result_type Cstate::RunProtectedCode(func function, Args&&... args) {
        typename func::result_type ret = typename func::result_type();
        __try {
            ret = function(std::forward<Args>(args)...);
        }
        __except(ExceptionHandler(GetExceptionCode(), ExceptionStatus::CSubsystem)) {
            fprintf(stderr, "First chance exception in C-code.\n");
        }
        return ret;
    }

你可以这样称呼它

std::function<int(int,int,int)> entry_f = entry;
RunProtectedCode(entry_f,1,2,3);

【讨论】:

  • 从 C++17 开始,调用可调用对象的惯用方式是使用 std::invoke
【解决方案2】:

您可以将所有参数绑定到您的函数,使其有效地成为 0 元仿函数,例如使用std::bind(在VC2010 中可用)或boost::bind(我更喜欢这个,因为VC 实现包含损坏的std::cref)。绑定可以在传递给RunProtectedCode之前在重载函数中完成,例如像这样:

template<typename R>
R(*f)() wrap(R(*f)())
{
    return f;
}

template<typename R, typename A>
boost::function<R(A)> wrap(R(*f)(), A a)
{
    return boost::bind(f, a);
}

template<typename R, typename A1, typename A2>
boost::function<R(A1, A2)> wrap(R(*f)(), A1 a1, A2 a2)
{
    return boost::bind(f, a1, a2);
}

【讨论】:

  • 另外值得注意的是,在 VS2010 中,std::bind copy 构造了它的参数大约 10 次。 boost::bind 和 VS2012 的 std::bind 在这方面表现也更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-18
  • 2013-08-07
  • 2018-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-15
相关资源
最近更新 更多