简体   繁体   English

我应该如何定义带有默认参数的 std::function 变量?

[英]How should I define a std::function variable with default arguments?

To set a std::function variable to a lambda function with default argument I can use auto as in:要将 std::function 变量设置为带有默认参数的 lambda 函数,我可以使用auto如下所示:

auto foo = [](int x = 10){cout << x << endl;};
foo();

This will print 10.这将打印 10。

But I want the foo variable to reside in a struct.但我希望 foo 变量驻留在结构中。 In a struct I cannot use auto .在结构中我不能使用auto

struct Bar
{
    auto foo = [](int x = 10}(cout << x << endl}; //error: non-static data member declared ‘auto’
};
Bar bar;
bar.foo();

Replacing auto with std::function用 std::function 替换auto

struct Bar
{
    std::function<void(int x = 10)> foo = [](int x = 10}(cout << x << endl}; //error: default arguments are only permitted for function parameters
};
Bar bar;
bar.foo();

or或者

struct Bar
{
    std::function<void(int)> foo = [](int x = 10}(cout << x << endl};
};
Bar bar;
bar.foo(); //error: no match for call to ‘(std::function<void(int)>) ()’

Without the struct and replacing auto for std::function:没有 struct 并用auto替换 std::function:

std::function<void(int x)> foo = [](int x = 10){cout << x << endl;};
foo(); //error: no match for call to ‘(std::function<void(int)>) ()’

So how should I declare foo?那么我应该如何声明 foo 呢?

The signature in std::function is based on how you plan to call it and not on how you construct/assign it. std::function的签名基于您计划如何调用它而不是您如何构造/分配它。 Since you want to call it two different ways, you'll need to store to different std::function objects, as in:由于您想以两种不同的方式调用它,因此您需要存储到不同的std::function对象,如下所示:

struct Call
{
    template<typename F>
    explicit Call(F f) : zero_(f), one_(std::move(f)) {}

    void operator()() { zero_(); }
    void operator()(int i) { one_(i); }

    std::function<void()>    zero_;
    std::function<void(int)> one_;
};

Alternatively, you can do the type erasure yourself (what std::function does behind the scenes) to only store the lambda once, as in:或者,您可以自己进行类型擦除( std::function在幕后所做的)只存储一次 lambda,如下所示:

class TECall
{
    struct Concept
    {   
        Concept() = default;
        Concept(Concept const&) = default;
        virtual ~Concept() = default;

        virtual Concept* clone() const = 0;

        virtual void operator()() = 0;
        virtual void operator()(int) = 0;
    };  

    template<typename T>
    struct Model final : Concept
    {   
        explicit Model(T t) : data(std::move(t)) {}
        Model* clone() const override { return new Model(*this); }

        void operator()() override { data(); }
        void operator()(int i) override { data(i); }

        T data;
    };  

    std::unique_ptr<Concept> object;

public:
    template<typename F>
    TECall(F f) : object(new Model<F>(std::move(f))) {}

    TECall(TECall const& that) : object(that.object ? that.object->clone() : nullptr) {}
    TECall(TECall&& that) = default;
    TECall& operator=(TECall that) { object = std::move(that.object); return *this; }

    void operator()() { (*object)(); }
    void operator()(int i) { (*object)(i); }
};

Don't know if that will help you, but you can store a lambda in a templated struct.不知道这是否对您有帮助,但您可以将 lambda 存储在模板化结构中。

template <typename F>
struct Bar {
  F foo;
  Bar (F fun): foo (std::move (fun)) {}
};

auto f = [](int x = 10) {cout << x << endl;};
Bar<decltype (f)> bar (f);
bar.foo();

auto makeFun = [](){return [](int x = 10) {cout << x << endl;};};

Bar<decltype (makeFun())> bar2 (makeFun());
bar2.foo();

In C++20 you will be able to do this:在 C++20 中,你将能够做到这一点:

struct foo {
    decltype([](int a = 10){std::cout << a << '\n';}) my_lambda{};
};

int main() {
    foo f;
    f.my_lambda();
    f.my_lambda(5);
}

Live on Godbolt住在 Godbolt

It does look a bit strange, but it works just fine.它看起来确实有点奇怪,但它工作得很好。

What makes this possible is the ability to use lambdas in unevaluated contexts and default construct stateless lambdas .使这成为可能的是在未评估的上下文中使用 lambdas默认构造无状态 lambdas 的能力

One way you could solve this would be to wrap your std::function in a functor object which implements the default arguments for you:您可以解决此问题的一种方法是将您的std::function包装在一个为您实现默认参数的函子对象中:

struct MyFunc
{
    void operator()(int x = 10) { f(x); }
    std::function<void(int x)> f;
};

struct Bar
{
    MyFunc foo = {[](int x){std::cout << x << "\n";}};
};

int main() {
    Bar bar;
    bar.foo();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM