gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 01:49:08 25 4
gpt4 key购买 nike

我正在尝试实现简单的 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 的函数参数传递给它?例如,我使用两个整数参数绑定(bind) BarExitFunc: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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com