将重载函数转换为专用函数模板
Convert overloaded functions to specialized function templates
我有一个当前针对不同数据类型重载的函数,它采用 lambda(函数指针)来初始化这些数据类型。我正在将它们转换为模板实例,但尚未成功。
Here's the overloaded version -
#include <iostream>
using namespace std;
void doSome(int (*func)(int &)){
int a;
a = 5;
int res = func(a);
cout << a << "\n";
}
void doSome(int (*func)(double &)){
double a;
a = 5.2;
int res = func(a);
cout << a << "\n";
}
int main() {
doSome([](int &a){
a += 2;
return 1;
});
doSome([](double &a){
a += 2.5;
return 1;
});
return 0;
}
请注意,为了简化起见,我以 int
和 double
为例,它们在实际代码中可能是一些完全不同(且复杂)的类型。
#include <iostream>
using namespace std;
template <typename F, typename S>
void doSome(F &func){
S a;
auto res = func(a);
cout << res << "\n";
}
template<>
void doSome<typename F, int> (F &func){
int a;
a = 5;
auto res = func(a);
cout << res << "\n";
}
template<>
void dpSome<typename F, double> (F &func){
double a;
a = 5.5
auto res = func(a);
cout << res << "\n";
}
int main() {
doSome([](int &a){
a += 2;
return 1;
});
doSome([](double &a){
a += 2.5;
return 1;
});
return 0;
}
此外,在调用模板函数时,如果我不必将 <any type hints>
传递给函数,那将是更好的解决方案。
您的方法存在一些问题。首先,您不能部分特化函数模板,所以这是不可能的。其次,您通过左值引用获取函数 - 这会阻止您传入 lambda,它是纯右值。
在这种情况下,只需在您的函数模板上添加一些 SFINAE 就很容易,这样一个函数仅在可以用 int&
调用时才参与重载决议,而另一个只能用 double&
调用:
template <class F>
auto doSome(F f)
-> decltype(f(std::declval<int&>()), void())
{
// int& case
}
template <class F>
auto doSome(F f)
-> decltype(f(std::declval<double&>()), void())
{
// double& case
}
如果您想制作 doSome()
的通用版本,它不使用 SFINAE 进行重载解析,它会变得有点复杂。
#include <type_traits> // For std::remove_reference_t.
namespace detail {
// Helper to isolate return and parameter types, for a single-parameter callable.
template<typename T>
struct isolate_types;
// Function.
template<typename R, typename P>
struct isolate_types<R(P)> { using Ret = R; using Param = P; };
// Function pointer.
template<typename R, typename P>
struct isolate_types<R(*)(P)> { using Ret = R; using Param = P; }
// Pointer-to-member-function. Used for lambdas & functors.
// Assumes const this pointer.
template<typename R, typename C, typename P>
struct isolate_types<R (C::*)(P) const> { using Ret = R; using Param = P; };
// Lambda. Uses lambda's operator().
// Credit goes to ecatmur:
template<typename T>
struct isolate_types : isolate_types<decltype(&std::remove_reference_t<T>::operator())> {};
// Individual type aliases.
template<typename T>
using IsolateReturn = typename isolate_types<T>::Ret;
template<typename T>
using IsolateParam = typename isolate_types<T>::Param;
// Internal values, used by doSome().
template<typename T> T value;
template<> constexpr int value<int> = 5;
template<> constexpr double value<double> = 5.2;
// Define others as needed...
} // namespace detail
template<typename F>
void doSome(F func) {
// Determine necessary types.
using Ret = detail::IsolateReturn<F>;
using Param = std::remove_reference_t<detail::IsolateParam<F>>;
// And voila.
Param a = detail::value<Param>;
Ret res = func(a); // Can also use auto, if Ret isn't needed elsewhere.
std::cout << a << "\n";
}
正在将其插入您的代码中...and it works。
请注意,我不确定这是否适用于所写的所有 lambda,而且它目前不适用于对函数的引用。但是,通过添加 isolate_types
.
的额外特化,它很容易扩展
我有一个当前针对不同数据类型重载的函数,它采用 lambda(函数指针)来初始化这些数据类型。我正在将它们转换为模板实例,但尚未成功。
Here's the overloaded version -
#include <iostream>
using namespace std;
void doSome(int (*func)(int &)){
int a;
a = 5;
int res = func(a);
cout << a << "\n";
}
void doSome(int (*func)(double &)){
double a;
a = 5.2;
int res = func(a);
cout << a << "\n";
}
int main() {
doSome([](int &a){
a += 2;
return 1;
});
doSome([](double &a){
a += 2.5;
return 1;
});
return 0;
}
请注意,为了简化起见,我以 int
和 double
为例,它们在实际代码中可能是一些完全不同(且复杂)的类型。
#include <iostream>
using namespace std;
template <typename F, typename S>
void doSome(F &func){
S a;
auto res = func(a);
cout << res << "\n";
}
template<>
void doSome<typename F, int> (F &func){
int a;
a = 5;
auto res = func(a);
cout << res << "\n";
}
template<>
void dpSome<typename F, double> (F &func){
double a;
a = 5.5
auto res = func(a);
cout << res << "\n";
}
int main() {
doSome([](int &a){
a += 2;
return 1;
});
doSome([](double &a){
a += 2.5;
return 1;
});
return 0;
}
此外,在调用模板函数时,如果我不必将 <any type hints>
传递给函数,那将是更好的解决方案。
您的方法存在一些问题。首先,您不能部分特化函数模板,所以这是不可能的。其次,您通过左值引用获取函数 - 这会阻止您传入 lambda,它是纯右值。
在这种情况下,只需在您的函数模板上添加一些 SFINAE 就很容易,这样一个函数仅在可以用 int&
调用时才参与重载决议,而另一个只能用 double&
调用:
template <class F>
auto doSome(F f)
-> decltype(f(std::declval<int&>()), void())
{
// int& case
}
template <class F>
auto doSome(F f)
-> decltype(f(std::declval<double&>()), void())
{
// double& case
}
如果您想制作 doSome()
的通用版本,它不使用 SFINAE 进行重载解析,它会变得有点复杂。
#include <type_traits> // For std::remove_reference_t.
namespace detail {
// Helper to isolate return and parameter types, for a single-parameter callable.
template<typename T>
struct isolate_types;
// Function.
template<typename R, typename P>
struct isolate_types<R(P)> { using Ret = R; using Param = P; };
// Function pointer.
template<typename R, typename P>
struct isolate_types<R(*)(P)> { using Ret = R; using Param = P; }
// Pointer-to-member-function. Used for lambdas & functors.
// Assumes const this pointer.
template<typename R, typename C, typename P>
struct isolate_types<R (C::*)(P) const> { using Ret = R; using Param = P; };
// Lambda. Uses lambda's operator().
// Credit goes to ecatmur:
template<typename T>
struct isolate_types : isolate_types<decltype(&std::remove_reference_t<T>::operator())> {};
// Individual type aliases.
template<typename T>
using IsolateReturn = typename isolate_types<T>::Ret;
template<typename T>
using IsolateParam = typename isolate_types<T>::Param;
// Internal values, used by doSome().
template<typename T> T value;
template<> constexpr int value<int> = 5;
template<> constexpr double value<double> = 5.2;
// Define others as needed...
} // namespace detail
template<typename F>
void doSome(F func) {
// Determine necessary types.
using Ret = detail::IsolateReturn<F>;
using Param = std::remove_reference_t<detail::IsolateParam<F>>;
// And voila.
Param a = detail::value<Param>;
Ret res = func(a); // Can also use auto, if Ret isn't needed elsewhere.
std::cout << a << "\n";
}
正在将其插入您的代码中...and it works。
请注意,我不确定这是否适用于所写的所有 lambda,而且它目前不适用于对函数的引用。但是,通过添加 isolate_types
.