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

后端 未结 4 1073
有刺的猬
有刺的猬 2021-02-07 08:48

To set a std::function variable to a lambda function with default argument I can use auto as in:

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


        
相关标签:
4条回答
  • 2021-02-07 09:19

    In C++20 you will be able to do this:

    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

    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.

    0 讨论(0)
  • 2021-02-07 09:32

    Don't know if that will help you, but you can store a lambda in a templated struct.

    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();
    
    0 讨论(0)
  • 2021-02-07 09:37

    One way you could solve this would be to wrap your std::function in a functor object which implements the default arguments for you:

    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();
    }
    
    0 讨论(0)
  • 2021-02-07 09:38

    The signature in std::function is based on how you plan to call it and not on how you construct/assign it. Since you want to call it two different ways, you'll need to store to different std::function objects, as 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_;
    };
    

    Alternatively, you can do the type erasure yourself (what std::function does behind the scenes) to only store the lambda once, as 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); }
    };
    
    0 讨论(0)
提交回复
热议问题