我应该如何使用默认参数定义std :: function变量?

时间:2014-04-07 15:29:16

标签: c++11 lambda std-function

要将std :: function变量设置为具有默认参数的lambda函数,我可以使用auto,如下所示:

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

这将打印10。

但我希望foo变量驻留在struct中。在结构中,我不能使用auto

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

用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();

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)>) ()’

没有结构并替换std :: function的auto

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

那我该如何申报foo?

4 个答案:

答案 0 :(得分:6)

std::function中的签名取决于您打算如何调用它,而不是基于您如何构建/分配它。由于您想以两种不同的方式调用它,因此您需要存储到不同的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_;
};

或者,您可以自己进行类型擦除(幕后的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); }
};

答案 1 :(得分:2)

不知道这对你有帮助,但你可以在一个模板化的结构中存储一个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();

答案 2 :(得分:0)

解决此问题的一种方法是将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();
}

答案 3 :(得分:0)

在C ++ 20中,您可以执行以下操作:

systemctl reload nginx

Live on Godbolt

它看起来确实有些奇怪,但是效果很好。

使之成为可能的是use lambdas in unevaluated contextsdefault construct stateless lambdas的能力。