As the title says, how can I have the following intent expressed in code? The requirements being the function pointer takes any type of arguments. Variadic doesn't work because of std::string
.
Note that I cannot directly use auto fp = <the lambda>
because fp
is a class member variable.
#include <iostream>
template<typename T1, typename T2>
void(*fp)(T1 t1, T2 t2) = [](auto a, auto b){
std::cout << a << "--"
<< b << std::endl;
};
int main(){
fp(1, 2);
fp('a', 'b');
}
A variable template is perfectly fine.
Even the way you initialize them is fine.
Just be aware it is a template for variables, not a variable storing a template (which cannot exist).
Thus when finally using it, things fall apart:
How should the compiler know which of the myriad potential instances you mean?
Simple, you have to actually tell it :
int main(){
fp<int, int>(1, 2);
fp<char, char>('a', 'b');
}
Of course, manually desugaring the lambda and getting an instance of it would be more practical :
struct {
template <class T1, class T2>
void operator()(T1 a, T2 b) const {
std::cout << a << "--" << b << std::endl;
};
} fp;
A shame we cannot simply give a lambda a name and let the compiler figure it out.
Brainstorming candidates for appropriate syntax:
struct A = []...;
struct B : []... {
};
using C = []...;
You cannot have such a template function pointer, but remember that a lambda is merely syntactical sugar, you can just write the class yourself.
class fp {
template<class AT, class BT>
void operator()(AT&& a, BT&& b) {
std::cout << a << "--" << b << std::endl;
};
};
class class_with_functionoid_member {
fp fn_;
};
And the more generic version would be that you can have the lambda as a member. You have to take the lambda type as a class parameter.
template<class fnT>
class class_with_lambda_member {
fnT fn_;
public:
class_with_lambda_member(fnT fn) : fn_(std::move(fn)) {}
};
The gist is that a function pointer is a type of runtime type erasure, and template member functions require compile time lazy instantiation, and C++ has no way to mix these two concepts. All the workarounds that come to mind revolve around explicitly listing out every possible combination of T1 and T2` in the "interface", which doesn't mix with a function pointer, but can work with a function pointer looking object.
struct erasable_functions {
virtual ~erasable_functions(){}
virtual void operator()(int, int)=0;
virtual void operator()(int, char)=0;
virtual void operator()(char, int)=0;
virtual void operator()(char, char)=0;
};
template<class lambdaT>
struct erased_functions : erasable_functions {
lambdaT lambda_;
erased_functions(lambdaT lambda) : lambda_(std::move(lambda)){}
virtual void operator()(int a, int b) {lambda_(a, b);
virtual void operator()(int a, char b) {lambda_(a, b);
virtual void operator()(char a, int b) {lambda_(a, b);
virtual void operator()(char a, char b) {lambda_(a, b);
};
template<class lambdaT>
erased_functions<lambdaT> erase_functions(lambdaT lambda)
{return {std::move(lambda)};}
struct class_with_functionoid_member {
erasable_functions* functions_;
class_with_functionoid_member(erasable_functions* functions) : functions_(functions){}
void operator()(int a, int b) {(*functions_)(a, b);
void operator()(int a, char b) {(*functions_)(a, b);
void operator()(char a, int b) {(*functions_)(a, b);
void operator()(char a, char b) {(*functions_)(a, b);
};
int main() {
auto lambda = erase_functions([](auto a, auto b) {
std::cout << a << "--" << b << std::endl;
};
class_with_functionoid_member c(&lambda);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.