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 << endl;};
foo();
This will print 10.
But I want the foo variable to reside in a struct. In a struct I cannot use 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
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:
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?
In C++ programming, we can provide default values for function parameters. If a function with default arguments is called without passing arguments, then the default parameters are used. However, if arguments are passed while calling the function, the default arguments are ignored.
Of the operators, only the function call operator and the operator new can have default arguments when they are overloaded. You can supply any default argument values in the function declaration or in the definition.
In computer programming, a default argument is an argument to a function that a programmer is not required to specify. In most programming languages, functions may take one or more arguments. Usually, each argument must be specified in full (this is the case in the C programming language).
Default arguments are only allowed in the parameter lists of function declarations and lambda-expressions, (since C++11) and are not allowed in the declarations of pointers to functions, references to functions, or in typedef declarations.
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); }
};
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();
}
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With