2014-04-07 13 views
5

Um eine std :: Funktion Variable auf eine Lambda-Funktion mit Standardargument gesetzt ich auto wie in verwenden:Wie sollte ich eine std :: function-Variable mit Standardargumenten definieren?

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

Das 10. in a druckt

Aber ich möchte, dass die foo Variable residieren Struktur. In einer Struktur kann ich auto nicht verwenden.

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

Ersetzen auto mit std :: function

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

oder

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

Ohne die Struktur und Ersetzen auto für 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)>)()’ 

Also, wie soll ich foo erklären?

+0

Es gibt keine Möglichkeit, eine 'std :: function' mit Standardargumenten zu machen. –

Antwort

4

Die Signatur in std::function basiert auf, wie Sie planen, es zu nennen und nicht, wie Sie es konstruieren/zuordnen. Da Sie es zwei verschiedene Arten aufrufen wollen, müssen Sie verschiedene std::function Objekte speichern, wie in:

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_; 
}; 

Alternativ können Sie den Typ Löschung selbst tun (was std::function hinter den Kulissen tut), um nur Speichern Sie das Lambda einmal, wie in:

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

Ich weiß nicht, ob Ihnen das hilft, aber Sie können ein Lambda in einer Templat-Struktur speichern.

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(); 
Verwandte Themen