如何从参数列表中推导出函数对象的返回类型? [英] How to deduce the return type of a function object from parameters list?

查看:230
本文介绍了如何从参数列表中推导出函数对象的返回类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个可以将向量< T> 变换为向量< R> 。下面是一个例子:

  auto v = std :: vector< int& {1,2,3,4}; 
auto r1 = select(v,[](int e){return e * e;}); // {1,4,9,16}
auto r2 = select(v,[](int e){return std :: to_string(e);}); // {1,2,3,4}

  template< typename T,typename R& 
std :: vector< R>选择(std :: vector< T> const& c,std :: function< R(T)> s)
{
std :: vector& v;
std :: transform(std :: begin(c),std :: end(c),std :: back_inserter(v),s);
return v;
}

  auto r1 = select(v,[](int e){return e * e;}); 

我得到:


错误C2660:'select':函数不接受2个参数


我必须显式调用 select< int,int> 工作。我不喜欢这样,因为类型是多余的。

  auto r1 = select  (int e){return e * e;}); // OK 

第二次尝试:

  template< typename T,typename R,typename Selector> 
std :: vector< R> select(std :: vector< T> const& c,Selector s)
{
std :: vector& v;
std :: transform(std :: begin(c),std :: end(c),std :: back_inserter(v),s);
return v;
}

结果是相同的错误,函数不接受2个参数。在这种情况下,我实际上必须提供第三个参数:

  auto r1 = select< int,int,std :: function< ; int(int)>>(v,[](int e){return e * e;}); 

第三次尝试:

  template< typename T,typename R,template< typename,typename>类选择器> 
std :: vector< R>选择(std :: vector< T> const& c,Selector< T,R)s
{
std :: vector& v;
std :: transform(std :: begin(c),std :: end(c),std :: back_inserter(v),s);
return v;
}

  auto r1 = select< int,int,std :: function< int(int)>>(v,[](int e){return e * e;}) 

错误是:


'select':Selector的模板参数无效,类模板需要



$ b

  auto r1 = select(v,[](int e){return e * e;}); 




错误C2660:'select':函数不接受2个参数


(我知道最后两次尝试并不是特别好。)



我如何写这个 select()模板函数来处理我放在开头的示例代码?

解决方案

选项#1:



基本 decltype() p>

 模板< typename T,typename F> 
auto select(const std :: vector< T>& c,F f)
- > std :: vector< decltype(f(c [0]))>
{
使用R = decltype(f(c [0]));
std :: vector< R> v;
std :: transform(std :: begin(c),std :: end(c),std :: back_inserter(v),f);
return v;
}



选项#2:



基本 std :: result_of< T> 使用:

  template< typename T,typename F,typename R = typename std :: result_of< F&(T)> :: type> 
std :: vector< R> select(const std :: vector< T>& c,F f)
{
std :: vector& v;
std :: transform(std :: begin(c),std :: end(c),std :: back_inserter(v),f);
return v;
}



选项#3:



高级 decltype()使用和完美转发(见注*):

  template< typename T,typename A,typename F> 
auto select(const std :: vector< T,A& c,F&& f)
- > std :: vector< typename std :: decay< decltype(std :: declval< typename std :: decay< F> :: type&>()(* c.begin()))
{
using R = typename std :: decay< decltype(std :: declval< typename std :: decay< F> :: type&>()(* c.begin())) > :: type;
std :: vector< R> v;
std :: transform(std :: begin(c),std :: end(c)
,std :: back_inserter(v)
,std :: forward& ));
return v;
}



选项#4:



高级 std :: result_of< T> 使用和完美转发(见注*):



template< typename T,typename A,typename F,typename R = typename std :: decay< typename std :: result_of< typename std :: decay< F> ; :: type&(typename std :: vector< T,A> :: const_reference)> :: type> :: type&
std :: vector< R> select(const std :: vector< T,A& c,F&& f)
{
std :: vector& v;
std :: transform(std :: begin(c),std :: end(c)
,std :: back_inserter(v)
,std :: forward& ));
return v;
}






*注:选项#3和#4假设 std :: transform 算法采用一个函数对象 by-value ,然后使用它作为一个非常量的值。这就是为什么可以看到这个奇怪的 typename std :: decay< F> :: type& 语法。如果函数对象应该在 select 函数本身内调用,并且结果类型不会被用作容器的模板参数(为了什么使用最外侧 std :: decay< T> ),则用于获得返回类型的正确且可移植的语法是:

  / *#3 * / using R = decltype(std :: forward< F>(f)(* c.begin()) ); 

/ *#4 * / typename R = typename std :: result_of< F&&(typename std :: vector< T,A> :: const_reference)> :: type


I'm trying to write a projection function that could transform a vector<T> into a vector<R>. Here is an example:

auto v = std::vector<int> {1, 2, 3, 4};
auto r1 = select(v, [](int e){return e*e; }); // {1, 4, 9, 16}
auto r2 = select(v, [](int e){return std::to_string(e); }); // {"1", "2", "3", "4"}

First attempt:

template<typename T, typename R>
std::vector<R> select(std::vector<T> const & c, std::function<R(T)> s)
{
   std::vector<R> v;
   std::transform(std::begin(c), std::end(c), std::back_inserter(v), s);
   return v;
}

But for

auto r1 = select(v, [](int e){return e*e; });

I get:

error C2660: 'select' : function does not take 2 arguments

I have to explicitly call select<int,int> to work. I don't like this because the types are redundant.

auto r1 = select<int, int>(v, [](int e){return e*e; }); // OK

Second attempt:

template<typename T, typename R, typename Selector>
std::vector<R> select(std::vector<T> const & c, Selector s)
{
   std::vector<R> v;
   std::transform(std::begin(c), std::end(c), std::back_inserter(v), s);
   return v;
}

The result is same error, function does not take 2 arguments. In this case I actually have to supply a 3rd type argument:

auto r1 = select<int, int, std::function<int(int)>>(v, [](int e){return e*e; });

Third attempt:

template<typename T, typename R, template<typename, typename> class Selector>
std::vector<R> select(std::vector<T> const & c, Selector<T,R> s)
{
   std::vector<R> v;
   std::transform(std::begin(c), std::end(c), std::back_inserter(v), s);
   return v;
}

For

auto r1 = select<int, int, std::function<int(int)>>(v, [](int e){return e*e; });

the error is:

'select' : invalid template argument for 'Selector', class template expected

For

auto r1 = select(v, [](int e){return e*e; });

error C2660: 'select' : function does not take 2 arguments

(I know the last two attempts are not particularly great.)

How can I write this select() template function to work for the sample code I put in the beginning?

解决方案

Option #1:

Basic decltype() usage:

template <typename T, typename F>
auto select(const std::vector<T>& c, F f)
    -> std::vector<decltype(f(c[0]))>
{
    using R = decltype(f(c[0]));
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c), std::back_inserter(v), f);
    return v;
}

Option #2:

Basic std::result_of<T> usage:

template <typename T, typename F, typename R = typename std::result_of<F&(T)>::type>
std::vector<R> select(const std::vector<T>& c, F f)
{
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c), std::back_inserter(v), f);
    return v;
}

Option #3:

Advanced decltype() usage and perfect-forwarding (see notes*):

template <typename T, typename A, typename F>
auto select(const std::vector<T, A>& c, F&& f)
    -> std::vector<typename std::decay<decltype(std::declval<typename std::decay<F>::type&>()(*c.begin()))>::type>
{
    using R = typename std::decay<decltype(std::declval<typename std::decay<F>::type&>()(*c.begin()))>::type;
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c)
                 , std::back_inserter(v)
                 , std::forward<F>(f));
    return v;
}

Option #4:

Advanced std::result_of<T> usage and perfect-forwarding (see notes*):

template <typename T, typename A, typename F, typename R = typename std::decay<typename std::result_of<typename std::decay<F>::type&(typename std::vector<T, A>::const_reference)>::type>::type>
std::vector<R> select(const std::vector<T, A>& c, F&& f)
{
    std::vector<R> v;
    std::transform(std::begin(c), std::end(c)
                 , std::back_inserter(v)
                 , std::forward<F>(f));
    return v;
}


* Note: Options #3 and #4 assume that the std::transform algorithm takes a function object by-value, and then uses it as a non-const lvalue. This is why one can see this strange typename std::decay<F>::type& syntax. If the function object is supposed to be called within the select function itself, and the result type is not going to be used as a container's template argument (for the purpose of what the outer-most std::decay<T> is used), then the correct and portable syntax for obtaining the return type is:

/*#3*/ using R = decltype(std::forward<F>(f)(*c.begin()));

/*#4*/ typename R = typename std::result_of<F&&(typename std::vector<T, A>::const_reference)>::type

这篇关于如何从参数列表中推导出函数对象的返回类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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