Is it possible to pass generic lambda as non-template argumentHow does generic lambda work in C++14?Template class generate errors in C++C++11 g++ strangeness (using defaulted template, lambda & remove_if)Compiling with gcc fails if using lambda function for QObject::connect()Distingushing between user and non-user types & templates specializationEnable method based on boolean template parameterPassing different lambdas to function template in c++Cross-platform “auto” keyword usage in lambdas: integral_constant as function argumentPassing variadic template to pthread_createConstructing std::function argument from lambdaInfering template type from function argument
Host telling me to cancel my booking in exchange for a discount?
Considerations when providing money to only one child out of two
Is it OK to accept a job opportunity while planning on not taking it?
Trivial non-dark twist in dark fantasy
Hats Question: Confusion Over Its Formulation
How can I remove studs and screws from the inside of drywall when installing a pocket door without needing to do paint and patch work on both sides?
Can the caster of Time Stop still use their bonus action or reaction?
Piece of fabric in planter, how to use it?
Why do we need an estimator to be consistent?
On a Gameboy, what happens when attempting to read/write external RAM while RAM is disabled?
Acoustic guitar chords' positions vs those of a Bass guitar
What would be the effects of (relatively) widespread precognition on the stock market?
Strange LED behavior
What is the AI assistant for the Iron Man Rescue armor?
Importance of moon phases for Apollo missions
"It is what it is"
What are "the high ends of castles" called?
How to handle not being able to attend as often as I'd like
Why does the salt in the oceans not sink to the bottom?
Finding Greatest Common Divisor using LuaLatex
My current job follows "worst practices". How can I talk about my experience in an interview without giving off red flags?
Can a creature sustain itself by eating its own severed body parts?
What does the following chess proverb mean: "Chess is a sea where a gnat may drink from and an elephant may bathe in."
Why was Quirrell said to be in the Black Forest if Voldemort was actually in Albania?
Is it possible to pass generic lambda as non-template argument
How does generic lambda work in C++14?Template class generate errors in C++C++11 g++ strangeness (using defaulted template, lambda & remove_if)Compiling with gcc fails if using lambda function for QObject::connect()Distingushing between user and non-user types & templates specializationEnable method based on boolean template parameterPassing different lambdas to function template in c++Cross-platform “auto” keyword usage in lambdas: integral_constant as function argumentPassing variadic template to pthread_createConstructing std::function argument from lambdaInfering template type from function argument
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I have a toy example that I'd like to modify architecturally to remove type dependency of Processor
on EmitterT
:
#include <iostream>
#include <utility>
using namespace std;
struct Emitter
void e(int) cout << "emitting intn";
void e(double) cout << "emitting doublen";
void e(char*) cout << "emitting char*n";
void e(const char*) cout << "emitting const char*n";
;
template <typename EmitterT>
struct Processor
Processor(EmitterT e) : e_e
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
EmitterT e_;
;
template<typename Emitter_>
Processor<Emitter_> makeProcessor(Emitter_ e) return Processor<Emitter_>(e);
int main()
Emitter em;
auto p = makeProcessor([&em](auto v)em.e(v););
p.process(1);
p.process("lol");
return 0;
Motivation
I'd like to decouple part responsible for utilizing results of processing from the processing itself. The Emitter
class structure is given to me, so I have to support overloaded functions.
I'd like to pass a lambda function to a processor that will use it. Kind of like a callback mechanism, however it must be a generic lambda, to support overloads.
What I've tried:
The example I wrote works, but it depends on Emitter
type as a template parameter. I don't like Processor
type to change based on Emitter
. It's also contagious, I have a real Processor
hierarchy and Emitter
spread like const
or worse.
After reading https://stackoverflow.com/a/17233649/1133179 I've tried playing with below struct as a member:
struct EmitterC
template<typename T>
void operator()(T value)
;
But I cannot figure out a way to defer implementation of Emitter
after Processor
when using it as a normal parameter. It worked out with a forward declaration and a reference EmitterC&
but it supports one only Emitter definition. The only way I could come up with was to drop lambda, and make virtual overloads in EmitterC
for every type I expect in Emitter
and use it as a base class.
So, Is there a way to pass the (generic) lambda as a parameter, so that Processor
type doesn't depend on Emitter
?
I am restricted to c++14, but I am interested in more modern standards as well if the have better support.
c++ lambda c++14
|
show 1 more comment
I have a toy example that I'd like to modify architecturally to remove type dependency of Processor
on EmitterT
:
#include <iostream>
#include <utility>
using namespace std;
struct Emitter
void e(int) cout << "emitting intn";
void e(double) cout << "emitting doublen";
void e(char*) cout << "emitting char*n";
void e(const char*) cout << "emitting const char*n";
;
template <typename EmitterT>
struct Processor
Processor(EmitterT e) : e_e
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
EmitterT e_;
;
template<typename Emitter_>
Processor<Emitter_> makeProcessor(Emitter_ e) return Processor<Emitter_>(e);
int main()
Emitter em;
auto p = makeProcessor([&em](auto v)em.e(v););
p.process(1);
p.process("lol");
return 0;
Motivation
I'd like to decouple part responsible for utilizing results of processing from the processing itself. The Emitter
class structure is given to me, so I have to support overloaded functions.
I'd like to pass a lambda function to a processor that will use it. Kind of like a callback mechanism, however it must be a generic lambda, to support overloads.
What I've tried:
The example I wrote works, but it depends on Emitter
type as a template parameter. I don't like Processor
type to change based on Emitter
. It's also contagious, I have a real Processor
hierarchy and Emitter
spread like const
or worse.
After reading https://stackoverflow.com/a/17233649/1133179 I've tried playing with below struct as a member:
struct EmitterC
template<typename T>
void operator()(T value)
;
But I cannot figure out a way to defer implementation of Emitter
after Processor
when using it as a normal parameter. It worked out with a forward declaration and a reference EmitterC&
but it supports one only Emitter definition. The only way I could come up with was to drop lambda, and make virtual overloads in EmitterC
for every type I expect in Emitter
and use it as a base class.
So, Is there a way to pass the (generic) lambda as a parameter, so that Processor
type doesn't depend on Emitter
?
I am restricted to c++14, but I am interested in more modern standards as well if the have better support.
c++ lambda c++14
1
In your code, there is no need to store emitter as a member, so you can simply accept it is a parameter as well.
– SergeyA
8 hours ago
You can make the constructor a templated function instead, and type-erase it into astd::function
class member.
– Sam Varshavchik
8 hours ago
3
@SamVarshavchik: what would the signature of thatstd::function
be?
– Vittorio Romeo
8 hours ago
The types of parameters the lambda takes, and its return value.
– Sam Varshavchik
7 hours ago
1
Type-erase the parameter to the lambda itself. At some point, somewhere, the type must be known, or determined someway. Nothing more can really be said about this, is is too vague, at this point.
– Sam Varshavchik
7 hours ago
|
show 1 more comment
I have a toy example that I'd like to modify architecturally to remove type dependency of Processor
on EmitterT
:
#include <iostream>
#include <utility>
using namespace std;
struct Emitter
void e(int) cout << "emitting intn";
void e(double) cout << "emitting doublen";
void e(char*) cout << "emitting char*n";
void e(const char*) cout << "emitting const char*n";
;
template <typename EmitterT>
struct Processor
Processor(EmitterT e) : e_e
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
EmitterT e_;
;
template<typename Emitter_>
Processor<Emitter_> makeProcessor(Emitter_ e) return Processor<Emitter_>(e);
int main()
Emitter em;
auto p = makeProcessor([&em](auto v)em.e(v););
p.process(1);
p.process("lol");
return 0;
Motivation
I'd like to decouple part responsible for utilizing results of processing from the processing itself. The Emitter
class structure is given to me, so I have to support overloaded functions.
I'd like to pass a lambda function to a processor that will use it. Kind of like a callback mechanism, however it must be a generic lambda, to support overloads.
What I've tried:
The example I wrote works, but it depends on Emitter
type as a template parameter. I don't like Processor
type to change based on Emitter
. It's also contagious, I have a real Processor
hierarchy and Emitter
spread like const
or worse.
After reading https://stackoverflow.com/a/17233649/1133179 I've tried playing with below struct as a member:
struct EmitterC
template<typename T>
void operator()(T value)
;
But I cannot figure out a way to defer implementation of Emitter
after Processor
when using it as a normal parameter. It worked out with a forward declaration and a reference EmitterC&
but it supports one only Emitter definition. The only way I could come up with was to drop lambda, and make virtual overloads in EmitterC
for every type I expect in Emitter
and use it as a base class.
So, Is there a way to pass the (generic) lambda as a parameter, so that Processor
type doesn't depend on Emitter
?
I am restricted to c++14, but I am interested in more modern standards as well if the have better support.
c++ lambda c++14
I have a toy example that I'd like to modify architecturally to remove type dependency of Processor
on EmitterT
:
#include <iostream>
#include <utility>
using namespace std;
struct Emitter
void e(int) cout << "emitting intn";
void e(double) cout << "emitting doublen";
void e(char*) cout << "emitting char*n";
void e(const char*) cout << "emitting const char*n";
;
template <typename EmitterT>
struct Processor
Processor(EmitterT e) : e_e
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
EmitterT e_;
;
template<typename Emitter_>
Processor<Emitter_> makeProcessor(Emitter_ e) return Processor<Emitter_>(e);
int main()
Emitter em;
auto p = makeProcessor([&em](auto v)em.e(v););
p.process(1);
p.process("lol");
return 0;
Motivation
I'd like to decouple part responsible for utilizing results of processing from the processing itself. The Emitter
class structure is given to me, so I have to support overloaded functions.
I'd like to pass a lambda function to a processor that will use it. Kind of like a callback mechanism, however it must be a generic lambda, to support overloads.
What I've tried:
The example I wrote works, but it depends on Emitter
type as a template parameter. I don't like Processor
type to change based on Emitter
. It's also contagious, I have a real Processor
hierarchy and Emitter
spread like const
or worse.
After reading https://stackoverflow.com/a/17233649/1133179 I've tried playing with below struct as a member:
struct EmitterC
template<typename T>
void operator()(T value)
;
But I cannot figure out a way to defer implementation of Emitter
after Processor
when using it as a normal parameter. It worked out with a forward declaration and a reference EmitterC&
but it supports one only Emitter definition. The only way I could come up with was to drop lambda, and make virtual overloads in EmitterC
for every type I expect in Emitter
and use it as a base class.
So, Is there a way to pass the (generic) lambda as a parameter, so that Processor
type doesn't depend on Emitter
?
I am restricted to c++14, but I am interested in more modern standards as well if the have better support.
c++ lambda c++14
c++ lambda c++14
asked 8 hours ago
luk32luk32
13k26 silver badges48 bronze badges
13k26 silver badges48 bronze badges
1
In your code, there is no need to store emitter as a member, so you can simply accept it is a parameter as well.
– SergeyA
8 hours ago
You can make the constructor a templated function instead, and type-erase it into astd::function
class member.
– Sam Varshavchik
8 hours ago
3
@SamVarshavchik: what would the signature of thatstd::function
be?
– Vittorio Romeo
8 hours ago
The types of parameters the lambda takes, and its return value.
– Sam Varshavchik
7 hours ago
1
Type-erase the parameter to the lambda itself. At some point, somewhere, the type must be known, or determined someway. Nothing more can really be said about this, is is too vague, at this point.
– Sam Varshavchik
7 hours ago
|
show 1 more comment
1
In your code, there is no need to store emitter as a member, so you can simply accept it is a parameter as well.
– SergeyA
8 hours ago
You can make the constructor a templated function instead, and type-erase it into astd::function
class member.
– Sam Varshavchik
8 hours ago
3
@SamVarshavchik: what would the signature of thatstd::function
be?
– Vittorio Romeo
8 hours ago
The types of parameters the lambda takes, and its return value.
– Sam Varshavchik
7 hours ago
1
Type-erase the parameter to the lambda itself. At some point, somewhere, the type must be known, or determined someway. Nothing more can really be said about this, is is too vague, at this point.
– Sam Varshavchik
7 hours ago
1
1
In your code, there is no need to store emitter as a member, so you can simply accept it is a parameter as well.
– SergeyA
8 hours ago
In your code, there is no need to store emitter as a member, so you can simply accept it is a parameter as well.
– SergeyA
8 hours ago
You can make the constructor a templated function instead, and type-erase it into a
std::function
class member.– Sam Varshavchik
8 hours ago
You can make the constructor a templated function instead, and type-erase it into a
std::function
class member.– Sam Varshavchik
8 hours ago
3
3
@SamVarshavchik: what would the signature of that
std::function
be?– Vittorio Romeo
8 hours ago
@SamVarshavchik: what would the signature of that
std::function
be?– Vittorio Romeo
8 hours ago
The types of parameters the lambda takes, and its return value.
– Sam Varshavchik
7 hours ago
The types of parameters the lambda takes, and its return value.
– Sam Varshavchik
7 hours ago
1
1
Type-erase the parameter to the lambda itself. At some point, somewhere, the type must be known, or determined someway. Nothing more can really be said about this, is is too vague, at this point.
– Sam Varshavchik
7 hours ago
Type-erase the parameter to the lambda itself. At some point, somewhere, the type must be known, or determined someway. Nothing more can really be said about this, is is too vague, at this point.
– Sam Varshavchik
7 hours ago
|
show 1 more comment
4 Answers
4
active
oldest
votes
This simplest solution is to make Emitter
a parameter to process
:
struct Processor
template <typename T, typename EmitterFn>
void process(T&& value, EmitterFn emit)
cout << "some processing... ";
emit(std::forward<T>(value));
;
However, if it must be a member of Processor
and you can enumerate the possible function signatures, you can use some kind of type erasure. std::function
or the proposed std::function_ref
won't work because they only allow a single function signature, but we can write our own overloaded_function_ref
:
template <typename Derived, typename Sig>
class function_ref_impl;
template <typename Derived, typename R, typename... Args>
class function_ref_impl<Derived, R(Args...)>
using fn_t = R(*)(void const*, Args...);
public:
auto operator()(Args... args) const -> R
return fn(static_cast<Derived const&>(*this).object, std::forward<Args>(args)...);
protected:
template <typename F,
std::enable_if_t<!std::is_base_of<function_ref_impl, F>::value, int> = 0>
explicit function_ref_impl(F const& f)
: fn[](void const* self, Args... args) -> R
return (*static_cast<F const*>(self))(std::forward<Args>(args)...);
private:
fn_t fn;
;
template <typename... Sig>
class overloaded_function_ref
: public function_ref_impl<overloaded_function_ref<Sig...>, Sig>...
public:
template <typename F,
std::enable_if_t<!std::is_base_of<overloaded_function_ref, F>::value, int> = 0>
overloaded_function_ref(F const& f)
: function_ref_impl<overloaded_function_ref, Sig>(f)...
, objectstd::addressof(f)
// Can be done pre-C++17, but it's not easy:
using function_ref_impl<overloaded_function_ref, Sig>::operator()...;
// This can be encapsulated with techniques such as the "passkey" idiom.
// Variadic friend expansion isn't a thing (`friend bases...`).
void const* object;
;
Live example
This does require C++17 for the using
, but that can be emulated in C++14; see the paper that introduced this feature: [P0195], or perhaps Boost HOF's
/* base */::operator()...match
can be massaged to do this. This is also just a function reference and not an owning function.
Then we can write:
struct Processor
template <typename T>
void process(T&& value)
cout << "some processing... ";
emit(std::forward<T>(value));
using emitter_t = overloaded_function_ref<
void(int),
void(double),
void(char*),
void(char const*)
>;
emitter_t emit;
;
Demo
add a comment |
IMHO: Inheritance is here for that.
#include <iostream>
#include <utility>
using namespace std;
struct BaseEmitter
virtual void e(int) =0;
virtual void e(double)=0;
virtual void e(char*)=0;
virtual void e(const char*)=0;
;
struct Emitter :public BaseEmitter
virtual void e(int) cout << "emitting intn";
virtual void e(double) cout << "emitting doublen";
virtual void e(char*) cout << "emitting char*n";
virtual void e(const char*) cout << "emitting const char*n";
;
struct Processor
BaseEmitter& e_;
Processor(BaseEmitter& e) : e_(e)
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
;
int main()
Emitter em;
auto p = Processor(em);
p.process(1);
p.process("lol");
return 0;
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
add a comment |
Is it possible to pass generic lambda as non-template argument
It is not possible to declare a non-template function that accepts a lambda as an argument. The type of a lambda is anonymous: It has no name. It is not possible to write a function declaration that accepts an argument of an anonymous type.
The type of the lambda can be deduced, which is why lambdas can be passed into function templates whose argument types are deduced.
While this answers the question, it does not offer a solution. I don't think a solution is going to be simple.
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.std::function
or the upcomingstd::function_ref
– Justin
8 hours ago
1
But thatstd::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...
– Max Langhof
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
2
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
1
@Justin: sadlystd::function_ref
was delayed to C++23.
– Vittorio Romeo
8 hours ago
|
show 2 more comments
If you are willing to pay a high runtime cost in exchange for minimal constraints, you can use std::function
with std::any
(for C++14, use boost::any
):
#include <iostream>
#include <utility>
#include <any>
#include <functional>
struct Processor
Processor(std::function<void(std::any)> e) : e_e
template <typename T>
void process(T&& value)
std::cout << "some processing... ";
e_(std::forward<T>(value));
std::function<void(std::any)> e_;
;
struct Emitter
void e(int) std::cout << "emitting intn";
void e(double) std::cout << "emitting doublen";
void e(char*) std::cout << "emitting char*n";
void e(const char*) std::cout << "emitting const char*n";
;
int main()
Emitter em;
auto p = Processor(
[&em](std::any any)
// This if-else chain isn't that cheap, but it's about the best
// we can do. Alternatives include:
// - Hashmap from `std::type_index` (possibly using a perfect hash)
// to a function pointer that implements this.
// - Custom `any` implementation which allows "visitation":
//
// any.visit<int, double, char*, char const*>([&em] (auto it)
// em.e(it);
// );
if (auto* i = std::any_cast<int>(&any))
em.e(*i);
else if (auto* d = std::any_cast<double>(&any))
em.e(*d);
else if (auto* cstr = std::any_cast<char*>(&any))
em.e(*cstr);
else
em.e(std::any_cast<char const*>(any));
);
p.process(1);
p.process("lol");
return 0;
std::any
and std::function
are both owning type erased wrappers. You may have heap allocations for this, or you might fit inside their small object optimization. You will have virtual function calls (or equivalent).
Compiler Explorer link
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57149664%2fis-it-possible-to-pass-generic-lambda-as-non-template-argument%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
This simplest solution is to make Emitter
a parameter to process
:
struct Processor
template <typename T, typename EmitterFn>
void process(T&& value, EmitterFn emit)
cout << "some processing... ";
emit(std::forward<T>(value));
;
However, if it must be a member of Processor
and you can enumerate the possible function signatures, you can use some kind of type erasure. std::function
or the proposed std::function_ref
won't work because they only allow a single function signature, but we can write our own overloaded_function_ref
:
template <typename Derived, typename Sig>
class function_ref_impl;
template <typename Derived, typename R, typename... Args>
class function_ref_impl<Derived, R(Args...)>
using fn_t = R(*)(void const*, Args...);
public:
auto operator()(Args... args) const -> R
return fn(static_cast<Derived const&>(*this).object, std::forward<Args>(args)...);
protected:
template <typename F,
std::enable_if_t<!std::is_base_of<function_ref_impl, F>::value, int> = 0>
explicit function_ref_impl(F const& f)
: fn[](void const* self, Args... args) -> R
return (*static_cast<F const*>(self))(std::forward<Args>(args)...);
private:
fn_t fn;
;
template <typename... Sig>
class overloaded_function_ref
: public function_ref_impl<overloaded_function_ref<Sig...>, Sig>...
public:
template <typename F,
std::enable_if_t<!std::is_base_of<overloaded_function_ref, F>::value, int> = 0>
overloaded_function_ref(F const& f)
: function_ref_impl<overloaded_function_ref, Sig>(f)...
, objectstd::addressof(f)
// Can be done pre-C++17, but it's not easy:
using function_ref_impl<overloaded_function_ref, Sig>::operator()...;
// This can be encapsulated with techniques such as the "passkey" idiom.
// Variadic friend expansion isn't a thing (`friend bases...`).
void const* object;
;
Live example
This does require C++17 for the using
, but that can be emulated in C++14; see the paper that introduced this feature: [P0195], or perhaps Boost HOF's
/* base */::operator()...match
can be massaged to do this. This is also just a function reference and not an owning function.
Then we can write:
struct Processor
template <typename T>
void process(T&& value)
cout << "some processing... ";
emit(std::forward<T>(value));
using emitter_t = overloaded_function_ref<
void(int),
void(double),
void(char*),
void(char const*)
>;
emitter_t emit;
;
Demo
add a comment |
This simplest solution is to make Emitter
a parameter to process
:
struct Processor
template <typename T, typename EmitterFn>
void process(T&& value, EmitterFn emit)
cout << "some processing... ";
emit(std::forward<T>(value));
;
However, if it must be a member of Processor
and you can enumerate the possible function signatures, you can use some kind of type erasure. std::function
or the proposed std::function_ref
won't work because they only allow a single function signature, but we can write our own overloaded_function_ref
:
template <typename Derived, typename Sig>
class function_ref_impl;
template <typename Derived, typename R, typename... Args>
class function_ref_impl<Derived, R(Args...)>
using fn_t = R(*)(void const*, Args...);
public:
auto operator()(Args... args) const -> R
return fn(static_cast<Derived const&>(*this).object, std::forward<Args>(args)...);
protected:
template <typename F,
std::enable_if_t<!std::is_base_of<function_ref_impl, F>::value, int> = 0>
explicit function_ref_impl(F const& f)
: fn[](void const* self, Args... args) -> R
return (*static_cast<F const*>(self))(std::forward<Args>(args)...);
private:
fn_t fn;
;
template <typename... Sig>
class overloaded_function_ref
: public function_ref_impl<overloaded_function_ref<Sig...>, Sig>...
public:
template <typename F,
std::enable_if_t<!std::is_base_of<overloaded_function_ref, F>::value, int> = 0>
overloaded_function_ref(F const& f)
: function_ref_impl<overloaded_function_ref, Sig>(f)...
, objectstd::addressof(f)
// Can be done pre-C++17, but it's not easy:
using function_ref_impl<overloaded_function_ref, Sig>::operator()...;
// This can be encapsulated with techniques such as the "passkey" idiom.
// Variadic friend expansion isn't a thing (`friend bases...`).
void const* object;
;
Live example
This does require C++17 for the using
, but that can be emulated in C++14; see the paper that introduced this feature: [P0195], or perhaps Boost HOF's
/* base */::operator()...match
can be massaged to do this. This is also just a function reference and not an owning function.
Then we can write:
struct Processor
template <typename T>
void process(T&& value)
cout << "some processing... ";
emit(std::forward<T>(value));
using emitter_t = overloaded_function_ref<
void(int),
void(double),
void(char*),
void(char const*)
>;
emitter_t emit;
;
Demo
add a comment |
This simplest solution is to make Emitter
a parameter to process
:
struct Processor
template <typename T, typename EmitterFn>
void process(T&& value, EmitterFn emit)
cout << "some processing... ";
emit(std::forward<T>(value));
;
However, if it must be a member of Processor
and you can enumerate the possible function signatures, you can use some kind of type erasure. std::function
or the proposed std::function_ref
won't work because they only allow a single function signature, but we can write our own overloaded_function_ref
:
template <typename Derived, typename Sig>
class function_ref_impl;
template <typename Derived, typename R, typename... Args>
class function_ref_impl<Derived, R(Args...)>
using fn_t = R(*)(void const*, Args...);
public:
auto operator()(Args... args) const -> R
return fn(static_cast<Derived const&>(*this).object, std::forward<Args>(args)...);
protected:
template <typename F,
std::enable_if_t<!std::is_base_of<function_ref_impl, F>::value, int> = 0>
explicit function_ref_impl(F const& f)
: fn[](void const* self, Args... args) -> R
return (*static_cast<F const*>(self))(std::forward<Args>(args)...);
private:
fn_t fn;
;
template <typename... Sig>
class overloaded_function_ref
: public function_ref_impl<overloaded_function_ref<Sig...>, Sig>...
public:
template <typename F,
std::enable_if_t<!std::is_base_of<overloaded_function_ref, F>::value, int> = 0>
overloaded_function_ref(F const& f)
: function_ref_impl<overloaded_function_ref, Sig>(f)...
, objectstd::addressof(f)
// Can be done pre-C++17, but it's not easy:
using function_ref_impl<overloaded_function_ref, Sig>::operator()...;
// This can be encapsulated with techniques such as the "passkey" idiom.
// Variadic friend expansion isn't a thing (`friend bases...`).
void const* object;
;
Live example
This does require C++17 for the using
, but that can be emulated in C++14; see the paper that introduced this feature: [P0195], or perhaps Boost HOF's
/* base */::operator()...match
can be massaged to do this. This is also just a function reference and not an owning function.
Then we can write:
struct Processor
template <typename T>
void process(T&& value)
cout << "some processing... ";
emit(std::forward<T>(value));
using emitter_t = overloaded_function_ref<
void(int),
void(double),
void(char*),
void(char const*)
>;
emitter_t emit;
;
Demo
This simplest solution is to make Emitter
a parameter to process
:
struct Processor
template <typename T, typename EmitterFn>
void process(T&& value, EmitterFn emit)
cout << "some processing... ";
emit(std::forward<T>(value));
;
However, if it must be a member of Processor
and you can enumerate the possible function signatures, you can use some kind of type erasure. std::function
or the proposed std::function_ref
won't work because they only allow a single function signature, but we can write our own overloaded_function_ref
:
template <typename Derived, typename Sig>
class function_ref_impl;
template <typename Derived, typename R, typename... Args>
class function_ref_impl<Derived, R(Args...)>
using fn_t = R(*)(void const*, Args...);
public:
auto operator()(Args... args) const -> R
return fn(static_cast<Derived const&>(*this).object, std::forward<Args>(args)...);
protected:
template <typename F,
std::enable_if_t<!std::is_base_of<function_ref_impl, F>::value, int> = 0>
explicit function_ref_impl(F const& f)
: fn[](void const* self, Args... args) -> R
return (*static_cast<F const*>(self))(std::forward<Args>(args)...);
private:
fn_t fn;
;
template <typename... Sig>
class overloaded_function_ref
: public function_ref_impl<overloaded_function_ref<Sig...>, Sig>...
public:
template <typename F,
std::enable_if_t<!std::is_base_of<overloaded_function_ref, F>::value, int> = 0>
overloaded_function_ref(F const& f)
: function_ref_impl<overloaded_function_ref, Sig>(f)...
, objectstd::addressof(f)
// Can be done pre-C++17, but it's not easy:
using function_ref_impl<overloaded_function_ref, Sig>::operator()...;
// This can be encapsulated with techniques such as the "passkey" idiom.
// Variadic friend expansion isn't a thing (`friend bases...`).
void const* object;
;
Live example
This does require C++17 for the using
, but that can be emulated in C++14; see the paper that introduced this feature: [P0195], or perhaps Boost HOF's
/* base */::operator()...match
can be massaged to do this. This is also just a function reference and not an owning function.
Then we can write:
struct Processor
template <typename T>
void process(T&& value)
cout << "some processing... ";
emit(std::forward<T>(value));
using emitter_t = overloaded_function_ref<
void(int),
void(double),
void(char*),
void(char const*)
>;
emitter_t emit;
;
Demo
edited 7 hours ago
answered 7 hours ago
JustinJustin
14.8k9 gold badges60 silver badges104 bronze badges
14.8k9 gold badges60 silver badges104 bronze badges
add a comment |
add a comment |
IMHO: Inheritance is here for that.
#include <iostream>
#include <utility>
using namespace std;
struct BaseEmitter
virtual void e(int) =0;
virtual void e(double)=0;
virtual void e(char*)=0;
virtual void e(const char*)=0;
;
struct Emitter :public BaseEmitter
virtual void e(int) cout << "emitting intn";
virtual void e(double) cout << "emitting doublen";
virtual void e(char*) cout << "emitting char*n";
virtual void e(const char*) cout << "emitting const char*n";
;
struct Processor
BaseEmitter& e_;
Processor(BaseEmitter& e) : e_(e)
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
;
int main()
Emitter em;
auto p = Processor(em);
p.process(1);
p.process("lol");
return 0;
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
add a comment |
IMHO: Inheritance is here for that.
#include <iostream>
#include <utility>
using namespace std;
struct BaseEmitter
virtual void e(int) =0;
virtual void e(double)=0;
virtual void e(char*)=0;
virtual void e(const char*)=0;
;
struct Emitter :public BaseEmitter
virtual void e(int) cout << "emitting intn";
virtual void e(double) cout << "emitting doublen";
virtual void e(char*) cout << "emitting char*n";
virtual void e(const char*) cout << "emitting const char*n";
;
struct Processor
BaseEmitter& e_;
Processor(BaseEmitter& e) : e_(e)
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
;
int main()
Emitter em;
auto p = Processor(em);
p.process(1);
p.process("lol");
return 0;
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
add a comment |
IMHO: Inheritance is here for that.
#include <iostream>
#include <utility>
using namespace std;
struct BaseEmitter
virtual void e(int) =0;
virtual void e(double)=0;
virtual void e(char*)=0;
virtual void e(const char*)=0;
;
struct Emitter :public BaseEmitter
virtual void e(int) cout << "emitting intn";
virtual void e(double) cout << "emitting doublen";
virtual void e(char*) cout << "emitting char*n";
virtual void e(const char*) cout << "emitting const char*n";
;
struct Processor
BaseEmitter& e_;
Processor(BaseEmitter& e) : e_(e)
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
;
int main()
Emitter em;
auto p = Processor(em);
p.process(1);
p.process("lol");
return 0;
IMHO: Inheritance is here for that.
#include <iostream>
#include <utility>
using namespace std;
struct BaseEmitter
virtual void e(int) =0;
virtual void e(double)=0;
virtual void e(char*)=0;
virtual void e(const char*)=0;
;
struct Emitter :public BaseEmitter
virtual void e(int) cout << "emitting intn";
virtual void e(double) cout << "emitting doublen";
virtual void e(char*) cout << "emitting char*n";
virtual void e(const char*) cout << "emitting const char*n";
;
struct Processor
BaseEmitter& e_;
Processor(BaseEmitter& e) : e_(e)
template <typename T>
void process(T&& value)
cout << "some processing... ";
e_(std::forward<T>(value));
;
int main()
Emitter em;
auto p = Processor(em);
p.process(1);
p.process("lol");
return 0;
answered 6 hours ago
Mel Viso MartinezMel Viso Martinez
5154 silver badges8 bronze badges
5154 silver badges8 bronze badges
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
add a comment |
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
This is a proposal to the motivation, not to the asked question.
– Mel Viso Martinez
6 hours ago
add a comment |
Is it possible to pass generic lambda as non-template argument
It is not possible to declare a non-template function that accepts a lambda as an argument. The type of a lambda is anonymous: It has no name. It is not possible to write a function declaration that accepts an argument of an anonymous type.
The type of the lambda can be deduced, which is why lambdas can be passed into function templates whose argument types are deduced.
While this answers the question, it does not offer a solution. I don't think a solution is going to be simple.
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.std::function
or the upcomingstd::function_ref
– Justin
8 hours ago
1
But thatstd::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...
– Max Langhof
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
2
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
1
@Justin: sadlystd::function_ref
was delayed to C++23.
– Vittorio Romeo
8 hours ago
|
show 2 more comments
Is it possible to pass generic lambda as non-template argument
It is not possible to declare a non-template function that accepts a lambda as an argument. The type of a lambda is anonymous: It has no name. It is not possible to write a function declaration that accepts an argument of an anonymous type.
The type of the lambda can be deduced, which is why lambdas can be passed into function templates whose argument types are deduced.
While this answers the question, it does not offer a solution. I don't think a solution is going to be simple.
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.std::function
or the upcomingstd::function_ref
– Justin
8 hours ago
1
But thatstd::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...
– Max Langhof
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
2
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
1
@Justin: sadlystd::function_ref
was delayed to C++23.
– Vittorio Romeo
8 hours ago
|
show 2 more comments
Is it possible to pass generic lambda as non-template argument
It is not possible to declare a non-template function that accepts a lambda as an argument. The type of a lambda is anonymous: It has no name. It is not possible to write a function declaration that accepts an argument of an anonymous type.
The type of the lambda can be deduced, which is why lambdas can be passed into function templates whose argument types are deduced.
While this answers the question, it does not offer a solution. I don't think a solution is going to be simple.
Is it possible to pass generic lambda as non-template argument
It is not possible to declare a non-template function that accepts a lambda as an argument. The type of a lambda is anonymous: It has no name. It is not possible to write a function declaration that accepts an argument of an anonymous type.
The type of the lambda can be deduced, which is why lambdas can be passed into function templates whose argument types are deduced.
While this answers the question, it does not offer a solution. I don't think a solution is going to be simple.
edited 7 hours ago
answered 8 hours ago
eerorikaeerorika
101k6 gold badges80 silver badges156 bronze badges
101k6 gold badges80 silver badges156 bronze badges
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.std::function
or the upcomingstd::function_ref
– Justin
8 hours ago
1
But thatstd::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...
– Max Langhof
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
2
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
1
@Justin: sadlystd::function_ref
was delayed to C++23.
– Vittorio Romeo
8 hours ago
|
show 2 more comments
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.std::function
or the upcomingstd::function_ref
– Justin
8 hours ago
1
But thatstd::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...
– Max Langhof
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
2
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
1
@Justin: sadlystd::function_ref
was delayed to C++23.
– Vittorio Romeo
8 hours ago
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.
std::function
or the upcoming std::function_ref
– Justin
8 hours ago
"It is not possible to declare a non-template function that accepts a lambda as an argument." Except you can have an implicit conversion to a non-template type, e.g.
std::function
or the upcoming std::function_ref
– Justin
8 hours ago
1
1
But that
std::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...– Max Langhof
8 hours ago
But that
std::function
wrapper can only be used to call one particular signature of the lambda, which is insufficient here...– Max Langhof
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
@MaxLanghof Hmm, yeah. Function wrapper might not be of use here.
– eerorika
8 hours ago
2
2
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.
overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
@MaxLanghof You could write your own which accepts multiple signatures, as long as you can enumerate the possible signatures. E.g.
overloaded_function_ref<void(int), void(double), void(char*), void(char const*)>
– Justin
8 hours ago
1
1
@Justin: sadly
std::function_ref
was delayed to C++23.– Vittorio Romeo
8 hours ago
@Justin: sadly
std::function_ref
was delayed to C++23.– Vittorio Romeo
8 hours ago
|
show 2 more comments
If you are willing to pay a high runtime cost in exchange for minimal constraints, you can use std::function
with std::any
(for C++14, use boost::any
):
#include <iostream>
#include <utility>
#include <any>
#include <functional>
struct Processor
Processor(std::function<void(std::any)> e) : e_e
template <typename T>
void process(T&& value)
std::cout << "some processing... ";
e_(std::forward<T>(value));
std::function<void(std::any)> e_;
;
struct Emitter
void e(int) std::cout << "emitting intn";
void e(double) std::cout << "emitting doublen";
void e(char*) std::cout << "emitting char*n";
void e(const char*) std::cout << "emitting const char*n";
;
int main()
Emitter em;
auto p = Processor(
[&em](std::any any)
// This if-else chain isn't that cheap, but it's about the best
// we can do. Alternatives include:
// - Hashmap from `std::type_index` (possibly using a perfect hash)
// to a function pointer that implements this.
// - Custom `any` implementation which allows "visitation":
//
// any.visit<int, double, char*, char const*>([&em] (auto it)
// em.e(it);
// );
if (auto* i = std::any_cast<int>(&any))
em.e(*i);
else if (auto* d = std::any_cast<double>(&any))
em.e(*d);
else if (auto* cstr = std::any_cast<char*>(&any))
em.e(*cstr);
else
em.e(std::any_cast<char const*>(any));
);
p.process(1);
p.process("lol");
return 0;
std::any
and std::function
are both owning type erased wrappers. You may have heap allocations for this, or you might fit inside their small object optimization. You will have virtual function calls (or equivalent).
Compiler Explorer link
add a comment |
If you are willing to pay a high runtime cost in exchange for minimal constraints, you can use std::function
with std::any
(for C++14, use boost::any
):
#include <iostream>
#include <utility>
#include <any>
#include <functional>
struct Processor
Processor(std::function<void(std::any)> e) : e_e
template <typename T>
void process(T&& value)
std::cout << "some processing... ";
e_(std::forward<T>(value));
std::function<void(std::any)> e_;
;
struct Emitter
void e(int) std::cout << "emitting intn";
void e(double) std::cout << "emitting doublen";
void e(char*) std::cout << "emitting char*n";
void e(const char*) std::cout << "emitting const char*n";
;
int main()
Emitter em;
auto p = Processor(
[&em](std::any any)
// This if-else chain isn't that cheap, but it's about the best
// we can do. Alternatives include:
// - Hashmap from `std::type_index` (possibly using a perfect hash)
// to a function pointer that implements this.
// - Custom `any` implementation which allows "visitation":
//
// any.visit<int, double, char*, char const*>([&em] (auto it)
// em.e(it);
// );
if (auto* i = std::any_cast<int>(&any))
em.e(*i);
else if (auto* d = std::any_cast<double>(&any))
em.e(*d);
else if (auto* cstr = std::any_cast<char*>(&any))
em.e(*cstr);
else
em.e(std::any_cast<char const*>(any));
);
p.process(1);
p.process("lol");
return 0;
std::any
and std::function
are both owning type erased wrappers. You may have heap allocations for this, or you might fit inside their small object optimization. You will have virtual function calls (or equivalent).
Compiler Explorer link
add a comment |
If you are willing to pay a high runtime cost in exchange for minimal constraints, you can use std::function
with std::any
(for C++14, use boost::any
):
#include <iostream>
#include <utility>
#include <any>
#include <functional>
struct Processor
Processor(std::function<void(std::any)> e) : e_e
template <typename T>
void process(T&& value)
std::cout << "some processing... ";
e_(std::forward<T>(value));
std::function<void(std::any)> e_;
;
struct Emitter
void e(int) std::cout << "emitting intn";
void e(double) std::cout << "emitting doublen";
void e(char*) std::cout << "emitting char*n";
void e(const char*) std::cout << "emitting const char*n";
;
int main()
Emitter em;
auto p = Processor(
[&em](std::any any)
// This if-else chain isn't that cheap, but it's about the best
// we can do. Alternatives include:
// - Hashmap from `std::type_index` (possibly using a perfect hash)
// to a function pointer that implements this.
// - Custom `any` implementation which allows "visitation":
//
// any.visit<int, double, char*, char const*>([&em] (auto it)
// em.e(it);
// );
if (auto* i = std::any_cast<int>(&any))
em.e(*i);
else if (auto* d = std::any_cast<double>(&any))
em.e(*d);
else if (auto* cstr = std::any_cast<char*>(&any))
em.e(*cstr);
else
em.e(std::any_cast<char const*>(any));
);
p.process(1);
p.process("lol");
return 0;
std::any
and std::function
are both owning type erased wrappers. You may have heap allocations for this, or you might fit inside their small object optimization. You will have virtual function calls (or equivalent).
Compiler Explorer link
If you are willing to pay a high runtime cost in exchange for minimal constraints, you can use std::function
with std::any
(for C++14, use boost::any
):
#include <iostream>
#include <utility>
#include <any>
#include <functional>
struct Processor
Processor(std::function<void(std::any)> e) : e_e
template <typename T>
void process(T&& value)
std::cout << "some processing... ";
e_(std::forward<T>(value));
std::function<void(std::any)> e_;
;
struct Emitter
void e(int) std::cout << "emitting intn";
void e(double) std::cout << "emitting doublen";
void e(char*) std::cout << "emitting char*n";
void e(const char*) std::cout << "emitting const char*n";
;
int main()
Emitter em;
auto p = Processor(
[&em](std::any any)
// This if-else chain isn't that cheap, but it's about the best
// we can do. Alternatives include:
// - Hashmap from `std::type_index` (possibly using a perfect hash)
// to a function pointer that implements this.
// - Custom `any` implementation which allows "visitation":
//
// any.visit<int, double, char*, char const*>([&em] (auto it)
// em.e(it);
// );
if (auto* i = std::any_cast<int>(&any))
em.e(*i);
else if (auto* d = std::any_cast<double>(&any))
em.e(*d);
else if (auto* cstr = std::any_cast<char*>(&any))
em.e(*cstr);
else
em.e(std::any_cast<char const*>(any));
);
p.process(1);
p.process("lol");
return 0;
std::any
and std::function
are both owning type erased wrappers. You may have heap allocations for this, or you might fit inside their small object optimization. You will have virtual function calls (or equivalent).
Compiler Explorer link
edited 6 hours ago
answered 7 hours ago
JustinJustin
14.8k9 gold badges60 silver badges104 bronze badges
14.8k9 gold badges60 silver badges104 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57149664%2fis-it-possible-to-pass-generic-lambda-as-non-template-argument%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
In your code, there is no need to store emitter as a member, so you can simply accept it is a parameter as well.
– SergeyA
8 hours ago
You can make the constructor a templated function instead, and type-erase it into a
std::function
class member.– Sam Varshavchik
8 hours ago
3
@SamVarshavchik: what would the signature of that
std::function
be?– Vittorio Romeo
8 hours ago
The types of parameters the lambda takes, and its return value.
– Sam Varshavchik
7 hours ago
1
Type-erase the parameter to the lambda itself. At some point, somewhere, the type must be known, or determined someway. Nothing more can really be said about this, is is too vague, at this point.
– Sam Varshavchik
7 hours ago