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