自动转发模板 [英] Forward a template auto

查看:91
本文介绍了自动转发模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(1)可以提取具有以下特征的可调用对象的返回类型和参数类型:

(1) One can extract the return type and the argument types of a callable with the following trait:

#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>

(2) Since C++17, one can define a template with template<auto>:


如果将模板参数声明为 auto ,则从相应的参数中推导其类型

If a template parameter is declared auto, its type is deduced from the corresponding argument.



问题



(3)然后,我应该能够提供一些语法糖:

Question

(3) I should then be able to provide some syntactic sugar:

template<auto callable>
using return_type = typename callable_trait<decltype(callable)>::return_type;

...但是效果不是很好...

... but it doesn't work too well ...

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不会t help ...

A lambda doesn't help ...

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)为函数返回的函数指针与您的专业化不符。使用lambda时,您得到的是lambda的类型,而不是 operator()。如果您还使用成员函数,也会遇到同样的问题,因为您的专业化与成员函数指针不匹配。

In the function case the issue here is that decltype(callable) for a function returns a function pointer, which doesn't match your specialization. With the lambda, you get the type of the lambda, not it's operator(). You'll have the same problem if you use a member function as well since your specialization doesn't match a member function pointer.

您需要的是可以接受的东西所有这些类型,然后为您提供 R(Args ...)。幸运的是,我们有 std :: function ,它是为执行此操作而构建的。它具有推论指南,使它可以采用任何函数类型并生成 std :: function< R(Args ...)> 以匹配其签名。使用 std :: function 您的代码可以成为

What you need is something that can take all of those types and give you an R(Args...) in return. Thankfully we have std::function and it is built to do just this thing. It has deduction guides that will allow it to take any function type and make a std::function<R(Args...)> to match its signature. Using a std::function your code can become

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头。 Clang无法推断 std :: function 以及早期版本的gcc和MSVS失败,原因如下:

but this only works on gcc head. Clang can't deduce the std::function and earlier versions of gcc and MSVS fail for the reason detailed here: Why is gcc failing when using lambda for non-type template parameter?

如果您切换到采用类型参数并使用 decltype ,则适用于gcc和MSVS,但是clang仍然存在问题推导指南

If you switch to taking a type parameter and use decltype is works on both gcc and MSVS but clang still has problems with the deduction guide

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");

这篇关于自动转发模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆