非捕获 lambda 和函数指针作为重载函数歧义中的参数
non-capturing lambda and function pointer as parameter in overloaded function ambiguity
#include <functional>
#include <iostream>
template<typename T>
void test( std::function< void ( const T& ) > f )
{
T val {};
f( val );
std::cout << "std::function" << std::endl;
}
template<typename T>
void test( void(*f) ( const T& ) )
{
T val {};
f( val );
std::cout << "function pointer" << std::endl;
}
int main()
{
auto capturing_var { 0 };
// Works because implicit conversion to function pointer isn't applied when lambda is capturing
test< int >( [ capturing_var ]( const int& x ) { } );
// Doesn't work because implicitly convertible to function pointer and makes ambiguity
// I want this line to work somehow, how can i make it worked with same client code ? Is it possible ?
test< int >( []( const int& x ) { } );
// This line is finer if it works, but in this case compiler cannot deduce T and also ambiguous if it could
test( []( const int& x ) { } );
// Works because of unary + operator so conversion to function ptr and i dont need to specify T
test( +[]( const int& x ) { } );
return 0;
}
实际上我只是希望这段代码可以在不更改 main()
中的任何内容的情况下运行,但我不确定这是否可行。
我可以省略带函数指针的重载函数,这样它就可以工作,但在那种情况下我需要指定 T
是什么。
注:我需要T
推导
您可以使用 this question 中描述的技术进行一些小的后处理。
最小示例:
template<typename Ret, typename Arg>
Arg argument_type(Ret(*)(Arg));
template<typename Ret, typename Fn, typename Arg>
Arg argument_type(Ret(Fn::*)(Arg) const);
template<typename Fn>
auto argument_type(Fn) -> decltype(argument_type(&Fn::operator()));
template<typename Arg, typename Fn>
struct argument {
static_assert(std::is_invocable_v<Fn, Arg>);
using type = Arg;
};
template<typename Fn>
struct argument<void, Fn>{
using type = decltype(argument_type(std::declval<Fn>()));
};
template<typename T = void, typename Fn>
void test(Fn fn) {
using Arg = std::decay_t<typename argument<T, Fn>::type>;
std::cout << "Arg = " << boost::typeindex::type_id_with_cvr<Arg>().pretty_name()
<< std::endl;
}
int main() {
int capturing_var;
test<int>([capturing_var](const int& x) {}); // Arg = int
test<int>([](const int& x) {}); // Arg = int
test([](const int& x) {}); // Arg = int
test(+[](const int& x) {}); // Arg = int
test<int>([](auto x) {}); // Arg = int
}
如果无法推导出参数类型,例如,对于可变 lambda,则必须提供(最后一个示例)。
#include <functional>
#include <iostream>
template<typename T>
void test( std::function< void ( const T& ) > f )
{
T val {};
f( val );
std::cout << "std::function" << std::endl;
}
template<typename T>
void test( void(*f) ( const T& ) )
{
T val {};
f( val );
std::cout << "function pointer" << std::endl;
}
int main()
{
auto capturing_var { 0 };
// Works because implicit conversion to function pointer isn't applied when lambda is capturing
test< int >( [ capturing_var ]( const int& x ) { } );
// Doesn't work because implicitly convertible to function pointer and makes ambiguity
// I want this line to work somehow, how can i make it worked with same client code ? Is it possible ?
test< int >( []( const int& x ) { } );
// This line is finer if it works, but in this case compiler cannot deduce T and also ambiguous if it could
test( []( const int& x ) { } );
// Works because of unary + operator so conversion to function ptr and i dont need to specify T
test( +[]( const int& x ) { } );
return 0;
}
实际上我只是希望这段代码可以在不更改 main()
中的任何内容的情况下运行,但我不确定这是否可行。
我可以省略带函数指针的重载函数,这样它就可以工作,但在那种情况下我需要指定 T
是什么。
注:我需要T
推导
您可以使用 this question 中描述的技术进行一些小的后处理。
最小示例:
template<typename Ret, typename Arg>
Arg argument_type(Ret(*)(Arg));
template<typename Ret, typename Fn, typename Arg>
Arg argument_type(Ret(Fn::*)(Arg) const);
template<typename Fn>
auto argument_type(Fn) -> decltype(argument_type(&Fn::operator()));
template<typename Arg, typename Fn>
struct argument {
static_assert(std::is_invocable_v<Fn, Arg>);
using type = Arg;
};
template<typename Fn>
struct argument<void, Fn>{
using type = decltype(argument_type(std::declval<Fn>()));
};
template<typename T = void, typename Fn>
void test(Fn fn) {
using Arg = std::decay_t<typename argument<T, Fn>::type>;
std::cout << "Arg = " << boost::typeindex::type_id_with_cvr<Arg>().pretty_name()
<< std::endl;
}
int main() {
int capturing_var;
test<int>([capturing_var](const int& x) {}); // Arg = int
test<int>([](const int& x) {}); // Arg = int
test([](const int& x) {}); // Arg = int
test(+[](const int& x) {}); // Arg = int
test<int>([](auto x) {}); // Arg = int
}
如果无法推导出参数类型,例如,对于可变 lambda,则必须提供(最后一个示例)。