转发模板自动
Forward a template auto
上下文
(1) 可以提取具有以下特征的可调用对象的 return 类型和参数类型:
#include <tuple>
template<class T>
struct callable_trait
{};
template<class R, class... Args>
struct callable_trait<R(Args...)>
{
using return_type = R;
using argument_types = std::tuple<Args...>;
};
(2) 从 C++17 开始,可以用 template<auto>
:
定义模板
If a template parameter is declared auto
, its type is deduced from the corresponding argument.
问题
(3) 然后我应该能够提供一些语法糖:
template<auto callable>
using return_type = typename callable_trait<decltype(callable)>::return_type;
...但效果不是很好...
void f();
void g(return_type<f>);
error: no type named 'return_type' in 'callable_trait<void (*)()>'
using return_type = typename callable_trait<decltype(callable)>::return_type;
^~~~~
lambda 没有帮助...
auto lambda= [](){};
void h(return_type<lambda>);
error: a non-type template parameter cannot have type '(lambda at <source>:19:14)'
void h(return_type<lambda>);
^
如何避免这种情况?
在函数案例中,这里的问题是 decltype(callable)
函数 return 是一个函数指针,这与您的专业化不符。使用 lambda,您可以获得 lambda 的类型,而不是 operator()
。如果您也使用成员函数,您将遇到同样的问题,因为您的特化与成员函数指针不匹配。
您需要的是可以采用所有这些类型并在 return 中为您提供 R(Args...)
的东西。值得庆幸的是,我们有 std::function
,它就是为做这件事而构建的。它有推导指南,允许它采用任何函数类型并制作 std::function<R(Args...)>
以匹配其签名。使用 std::function
你的代码可以变成
template<class T>
struct callable_trait
{};
template<class R, class... Args>
struct callable_trait<std::function<R(Args...)>>
{
using return_type = R;
using argument_types = std::tuple<Args...>;
static constexpr size_t argument_count = sizeof...(Args);
};
template<auto callable>
using return_type = typename callable_trait<decltype(std::function{callable})>::return_type;
template<auto callable>
static constexpr size_t argument_count = callable_trait<decltype(std::function{callable})>::argument_count;
void f();
void g(return_type<f>);
auto lambda = [](){};
void h(return_type<lambda>);
void e(int, int, int);
static_assert(argument_count<e> == 3, "oh no");
但这只适用于 gcc head. Clang can't deduce the std::function
and earlier versions of gcc and MSVS fail for the reason detailed here:
如果您切换到采用类型参数并使用 decltype
在 gcc 和 MSVS 上都有效,但 clang 仍然存在推导指南的问题
template<class T>
struct callable_trait
{};
template<class R, class... Args>
struct callable_trait<std::function<R(Args...)>>
{
using return_type = R;
using argument_types = std::tuple<Args...>;
static constexpr size_t argument_count = sizeof...(Args);
};
template<typename callable>
using return_type = typename callable_trait<decltype(std::function{std::declval<callable>()})>::return_type;
template<typename callable>
static constexpr size_t argument_count = callable_trait<decltype(std::function{std::declval<callable>()})>::argument_count;
void f();
void g(return_type<decltype(f)>);
auto lambda = [](){};
void h(return_type<decltype(lambda)>);
void e(int, int, int);
static_assert(argument_count<decltype(e)> == 3, "oh no");
上下文
(1) 可以提取具有以下特征的可调用对象的 return 类型和参数类型:
#include <tuple>
template<class T>
struct callable_trait
{};
template<class R, class... Args>
struct callable_trait<R(Args...)>
{
using return_type = R;
using argument_types = std::tuple<Args...>;
};
(2) 从 C++17 开始,可以用 template<auto>
:
If a template parameter is declared
auto
, its type is deduced from the corresponding argument.
问题
(3) 然后我应该能够提供一些语法糖:
template<auto callable>
using return_type = typename callable_trait<decltype(callable)>::return_type;
...但效果不是很好...
void f();
void g(return_type<f>);
error: no type named 'return_type' in 'callable_trait<void (*)()>' using return_type = typename callable_trait<decltype(callable)>::return_type; ^~~~~
lambda 没有帮助...
auto lambda= [](){};
void h(return_type<lambda>);
error: a non-type template parameter cannot have type '(lambda at <source>:19:14)' void h(return_type<lambda>); ^
如何避免这种情况?
在函数案例中,这里的问题是 decltype(callable)
函数 return 是一个函数指针,这与您的专业化不符。使用 lambda,您可以获得 lambda 的类型,而不是 operator()
。如果您也使用成员函数,您将遇到同样的问题,因为您的特化与成员函数指针不匹配。
您需要的是可以采用所有这些类型并在 return 中为您提供 R(Args...)
的东西。值得庆幸的是,我们有 std::function
,它就是为做这件事而构建的。它有推导指南,允许它采用任何函数类型并制作 std::function<R(Args...)>
以匹配其签名。使用 std::function
你的代码可以变成
template<class T>
struct callable_trait
{};
template<class R, class... Args>
struct callable_trait<std::function<R(Args...)>>
{
using return_type = R;
using argument_types = std::tuple<Args...>;
static constexpr size_t argument_count = sizeof...(Args);
};
template<auto callable>
using return_type = typename callable_trait<decltype(std::function{callable})>::return_type;
template<auto callable>
static constexpr size_t argument_count = callable_trait<decltype(std::function{callable})>::argument_count;
void f();
void g(return_type<f>);
auto lambda = [](){};
void h(return_type<lambda>);
void e(int, int, int);
static_assert(argument_count<e> == 3, "oh no");
但这只适用于 gcc head. Clang can't deduce the std::function
and earlier versions of gcc and MSVS fail for the reason detailed here:
如果您切换到采用类型参数并使用 decltype
在 gcc 和 MSVS 上都有效,但 clang 仍然存在推导指南的问题
template<class T>
struct callable_trait
{};
template<class R, class... Args>
struct callable_trait<std::function<R(Args...)>>
{
using return_type = R;
using argument_types = std::tuple<Args...>;
static constexpr size_t argument_count = sizeof...(Args);
};
template<typename callable>
using return_type = typename callable_trait<decltype(std::function{std::declval<callable>()})>::return_type;
template<typename callable>
static constexpr size_t argument_count = callable_trait<decltype(std::function{std::declval<callable>()})>::argument_count;
void f();
void g(return_type<decltype(f)>);
auto lambda = [](){};
void h(return_type<decltype(lambda)>);
void e(int, int, int);
static_assert(argument_count<decltype(e)> == 3, "oh no");