如何从参数列表中推导出函数对象的返回类型? [英] How to deduce the return type of a function object from parameters list?
问题描述
我想写一个可以将向量< 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屋!