c++ - ScopedExit 实现 : pass arguments to the function object

标签 c++ c++11 function-pointers

我正在尝试实现简单的 ScopedExit 类。代码如下:

#include <iostream>
#include <functional>

template<class R, class... Args>
class ScopedExit
{
public:
    ScopedExit(std::function<R(Args...)> exitFunction)
    {
        exitFunc_ = exitFunction; 
    }

    ~ScopedExit()
    {
        exitFunc_();
    }
private:
    std::function<R(Args...)> exitFunc_;
};

template<>
class ScopedExit<void>
{
public:
    ScopedExit(std::function<void ()> exitFunction)
    {
        exitFunc_ = exitFunction; 
    }

    ~ScopedExit()
    {
        exitFunc_();
    }
private:
    std::function<void ()> exitFunc_;
};

void foo()
{
    std::cout << "foo() called\n";
}

class Bar
{
public:
    void BarExitFunc(int x, int y)
    {
        std::cout << "BarExitFunc called with x =" << x << "y = " << y << "\n";
    }
};

int main()
{
    Bar b;
    std::cout << "Register scoped exit func\n";
    {
        ScopedExit<void, int, int> exitGuardInner(std::bind(&Bar::BarExitFunc, &b, 18, 11));
    }
    ScopedExit exitGuardOutter(foo);
    std::cout << "About to exit from the scope\n";
    return 0;
}

所以,有几个问题:

  1. 如何将 exit 的函数参数传递给它?例如,我将 BarExitFunc 与两个整数参数绑定(bind):18 和 11。那么如何将它传递给析构函数中的 exitFunc_ 呢?我想我需要像使用 std::forward<> 调用函数之类的东西。

  2. gcc 4.7.2(来自 ideone.com)提示 exitGuardOutter。它说:

prog.cpp:60:16: error: missing template arguments before ‘exitGuardOutter’

prog.cpp:60:16: error: expected ‘;’ before ‘exitGuardOutter’

提前致谢。

最佳答案

How to pass exit's function arguments to it? For example, I bind BarExitFunc with two integer arguments: 18 and 11. So how can I pass it to the exitFunc_ in the destructor?

我看不出有任何理由将参数传递给 exitFunc_在析构函数中调用时。无论您做什么,您都必须在 ScopedExit 中预先提供这些参数。无论如何,构造函数。

最直接的方法就是使用 function<R()>bind定义站点上的任何必需参数,就像您已经在做的那样:

ScopedExit<R> guard(std::bind(someFunction, someArg, otherArg));

这使您可以完全摆脱可变参数模板参数并大大简化您的模板很多


现在,如果困扰您的是您必须输入 std::bind你宁愿使用这样的语法:

ScopedExit<R> guard(someFunction, someArg, otherArg);

真的,我不明白这一点,因为它使模板变得更加复杂,但为什么不...只需在构造函数本身中绑定(bind)/转发参数,并仍然存储 function<R()> :

template<typename... Args>
ScopedExit(std::function<R(Args...)> exitFunction, Args&&... args)
{
    exitFunc_ = std::bind(exitFunction, std::forward<Args>(args)...); 
}

现在你系统地bind即使没有要绑定(bind)的参数,该函数也会被调用,因此您可能需要专门化您的类以避免这种无用的 bind当没有争论时。这留作练习。


gcc 4.7.2 (from ideone.com) complains about exitGuardOutter

这是因为foo不是std::function并且编译器无法推断出正确的模板参数。正如 @ForEveR 已经提到的,你可以将你的保护变量定义为 ScopedExit<void> guard(foo); .

或者,把它全部包装起来并记住我首先说的话(bind最好从你的模板中删除并在你的守卫的定义站点中使用)你可以摆脱的std::function在构造函数中并泛化为任何仿函数(顺便说一句,这就是标准库在需要仿函数/回调时的做法)。对于存储,您可以使用 std::function<void()>因为它也接受非 void 返回类型:

class ScopedExit
{
public:
    template<typename Functor>
    ScopedExit(Functor exitFunction)
    {
        exitFunc_ = exitFunction; 
    }

    ~ScopedExit()
    {
        exitFunc_();
    }
private:
    std::function<void()> exitFunc_;
};

int foo() { return 0; }

struct Bar {
  void bye(int, int) {}
};

struct Baz {
  void operator ()() {}
};

int main() {
    const std::string what = "lambda!";
    ScopedExit guard1([&]() { std::cout << "yay a " << what << std::endl; });

    ScopedExit guard2(foo); // note how std::function<void()> accepts non-void return types

    Bar b;
    ScopedExit guard3(std::bind(&Bar::bye, &b, 1, 2));

    ScopedExit guard4(Baz());
}

请注意,您的原始可变参数模板类现在如何成为一个灵活的非模板类,只有一个模板化构造函数,其模板参数是自动推导的,并且几乎接受[参见下面的注释]任何类型你可以考虑一下仿函数。


注意:我说几乎任何仿函数,因为这不适用于默认参数:

void foobar(int = 0) {}
ScopedExit guard5(foobar); // error: too few arguments to function

即使您存储了 Functor直接代替 std::function<void()>无论如何,你都无法使用默认参数(即使使用默认参数, foobar 的签名仍然是 void(int) ),所以人们总是必须在定义站点处理这种极端情况,如下所示:

void foobar(int = 0) {}
ScopedExit guard5([]() { foobar(); });

关于c++ - ScopedExit 实现 : pass arguments to the function object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16917821/

相关文章:

c++ - 抛出的异常 : read access violation. **node** 是 0xDDDDDDDD。发生

c++ - 如何更新此神经网络以使用图像像素数据

c++ - 如何解析像 std::allocator_traits 这样的可选嵌套类型?

c++ - 通过指针调用具有未知参数计数的函数的简单方法

c++ - 获取 this->c1->c2->c3->myFunc() 的函数指针;

c++ - 模板是否需要重载构造函数?

c++ - 交换 Qt 小部件

c++ - 如何在构造函数中初始化 vector 大小?

c++ - 为什么不能将类的类型成员作为模板参数传递?

C函数指针转换为另一个函数指针