模板函数的包装器
Wrapper for templated functions
我想要完成的是以下内容:
// or any templated function
template <typename... Args>
void function(Args... args) {}
// wrapper
void launch(???) { ??? }
int main()
{
// first option
launch(function, 1, 2, 3, 4);
// second option
launch<function>(1, 2, 3, 4);
}
据我所知,第一个选项是不可能的,因为我必须传递专门的模板函数(我试图避免)。
对于第二个选项,我不知道是否可行,我想出了以下不起作用实现:
template <template <typename...> class Function, typename... Args>
void launch(Args... args)
{
Function<Args...>(args...);
}
这最终给了我:
main.cpp:18:5: error: no matching function for call to 'launch'
launch<function>(1, 2, 3, 4);
^~~~~~~~~~~~~~~~
main.cpp:9:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Function'
void launch(Args... args)
^
1 error generated.
那么,这样的事情有可能吗?
除了调用它们(并推导参数)或实例化它们(通过手动指定模板参数)。
我相信也有一些小众情况,可以推导出模板参数并在没有实际调用的情况下选择特定的实例化,但它们在这里没有帮助 AMA 的回答显示了如何做到这一点!
通用 lambda 可能会或可能不会帮助您解决问题,但您需要为每个要制作的函数模板使用一个这样的转发 lambda "passable":
#include <functional>
// or any templated function
template <typename Arg1, typename Arg2>
void function(Arg1 arg1, Arg2 arg2) {}
int main()
{
auto wrapper = [](auto arg1, auto arg2) {
return function(arg1, arg2);
};
std::invoke(wrapper, 1, 2);
}
(Perfect-forwarding 到具有可变 lambda 的可变函数会更复杂。)
所以你不妨首先以函子结构的形式编写函数模板,或者以从 non-template 函数返回的 lambdas 的形式编写。
怎么样:
template <typename ... Args>
void launch(void(*func)(Args...), Args&&... args) {
func(std::forward<Args>(args)...);
}
呼叫launch
:
launch(function, 1, 2, 3, 4);
惯用的方法是推断可调用对象的类型,就好像它是任何类型一样,而不关心事物的 template-ness:
template <typename F, typename ... Args>
auto launch(F f, Args&&... args) -> decltype(auto) {
return f(std::forward<Args>(args)...);
}
它还会转发函数的return值。
然后,要发送您的模板化函数,您必须将函数提升为 lambda:
auto function_lift = [](auto&&... args)
noexcept(noexcept(function(std::forward<decltype(args)>(args)...)))
-> decltype(function(std::forward<decltype(args)>(args)...))
{
return function(std::forward<decltype(args)>(args)...);
};
// also works with defaulted parameters.
launch(function_lift, 1, 2, 3, 4);
创建那些提升函数非常冗长。这种情况下verbose-ness的答案当然是宏:
#define LIFT(lift_function) [](auto&&... args) \
noexcept(noexcept(lift_function(std::forward<decltype(args)>(args)...))) \
-> decltype(lift_function(std::forward<decltype(args)>(args)...)) \
{ \
return lift_function(std::forward<decltype(args)>(args)...); \
}
现在您可以调用包装器了:
launch(LIFT(function), 5, 4, 3, 2);
我想要完成的是以下内容:
// or any templated function
template <typename... Args>
void function(Args... args) {}
// wrapper
void launch(???) { ??? }
int main()
{
// first option
launch(function, 1, 2, 3, 4);
// second option
launch<function>(1, 2, 3, 4);
}
据我所知,第一个选项是不可能的,因为我必须传递专门的模板函数(我试图避免)。
对于第二个选项,我不知道是否可行,我想出了以下不起作用实现:
template <template <typename...> class Function, typename... Args>
void launch(Args... args)
{
Function<Args...>(args...);
}
这最终给了我:
main.cpp:18:5: error: no matching function for call to 'launch'
launch<function>(1, 2, 3, 4);
^~~~~~~~~~~~~~~~
main.cpp:9:6: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Function'
void launch(Args... args)
^
1 error generated.
那么,这样的事情有可能吗?
除了调用它们(并推导参数)或实例化它们(通过手动指定模板参数)。
我相信也有一些小众情况,可以推导出模板参数并在没有实际调用的情况下选择特定的实例化,但它们在这里没有帮助 AMA 的回答显示了如何做到这一点!
通用 lambda 可能会或可能不会帮助您解决问题,但您需要为每个要制作的函数模板使用一个这样的转发 lambda "passable":
#include <functional>
// or any templated function
template <typename Arg1, typename Arg2>
void function(Arg1 arg1, Arg2 arg2) {}
int main()
{
auto wrapper = [](auto arg1, auto arg2) {
return function(arg1, arg2);
};
std::invoke(wrapper, 1, 2);
}
(Perfect-forwarding 到具有可变 lambda 的可变函数会更复杂。)
所以你不妨首先以函子结构的形式编写函数模板,或者以从 non-template 函数返回的 lambdas 的形式编写。
怎么样:
template <typename ... Args>
void launch(void(*func)(Args...), Args&&... args) {
func(std::forward<Args>(args)...);
}
呼叫launch
:
launch(function, 1, 2, 3, 4);
惯用的方法是推断可调用对象的类型,就好像它是任何类型一样,而不关心事物的 template-ness:
template <typename F, typename ... Args>
auto launch(F f, Args&&... args) -> decltype(auto) {
return f(std::forward<Args>(args)...);
}
它还会转发函数的return值。
然后,要发送您的模板化函数,您必须将函数提升为 lambda:
auto function_lift = [](auto&&... args)
noexcept(noexcept(function(std::forward<decltype(args)>(args)...)))
-> decltype(function(std::forward<decltype(args)>(args)...))
{
return function(std::forward<decltype(args)>(args)...);
};
// also works with defaulted parameters.
launch(function_lift, 1, 2, 3, 4);
创建那些提升函数非常冗长。这种情况下verbose-ness的答案当然是宏:
#define LIFT(lift_function) [](auto&&... args) \
noexcept(noexcept(lift_function(std::forward<decltype(args)>(args)...))) \
-> decltype(lift_function(std::forward<decltype(args)>(args)...)) \
{ \
return lift_function(std::forward<decltype(args)>(args)...); \
}
现在您可以调用包装器了:
launch(LIFT(function), 5, 4, 3, 2);