[英]How to deduce the return type of a std::bind object for template use?
我有一个基本上只管理自定义类型向量的类。 为了减轻我一遍又一遍地编写相同的迭代循环,我编写了以下构造:
template<typename T>
uint64_t ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
{
return std::accumulate(vec.begin(), vec.end(), 0, [&](uint64_t acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
然后像这样调用:
ACCUMULATE_ON_VECTOR(_myVec, std::bind(&MyClass::someMethod, std::placeholders::_1));
这在概念上非常有效,但由于我有很多方法返回不同的整数类型(有符号/无符号,有符号/无符号长),我想抽象出现在硬编码的uint64_t因为我得到了编译器警告到处都是。 为此,我需要获取绑定对象的返回类型。 我可以用decltype以某种方式做到这一点吗? 我正在寻找的是:
template<typename T>
<new deduced type> ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
{
return std::accumulate(vec.begin(), vec.end(), 0, [&](<new deduced type> acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
你可以使用std::result_of
来做到这一点:
template<typename Func>
typename std::result_of<Func(MyClass*)>::type
ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> &vec, Func method)
{
using ResultType = typename std::result_of<Func(MyClass*)>::type;
return std::accumulate(vec.begin(), vec.end(), ResultType{},
[&](typename std::result_of<Func(MyClass*)>::type acc,
const MyClass* c)
{
return acc + (c ? method(c) : ResultType{});
});
}
注意我正在初始化返回类型而不是使用整数文字零。
将函数参数包装在std::function<ResultT(MyClass*)>
可能更具可读性:accumulate函数将直接模板化结果类型,将责任推到调用站点。
顺便说一句,你不需要这里的auto
/尾随返回类型技术,因为返回类型不依赖于参数列表,只依赖于模板参数 - 尽管如此,我认为它看起来稍微好一些:
template<typename Func>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> &vec,
Func method)
-> typename std::result_of<Func(MyClass*)>::type
{
std::bind
有一个名为result_type
的成员类型
1)如果F是指向函数的指针或指向成员函数的指针,则result_type是F的返回类型。如果F是具有嵌套typedef result_type的类类型,则result_type是F :: result_type。 否则,不定义result_type。
2)result_type正好是R.
我们可以使用跟踪返回类型
template<typename T>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method) -> typename T::result_type
{
typename T::result_type begin = 0;
return std::accumulate(vec.begin(), vec.end(), begin, [&](typename T::result_type acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
这适用于C ++ 11及更高版本。
我还添加了typename T::result_type begin = 0;
到函数,所以传递给accumulate的类型与函数的返回类型相同。 因为你刚才有0
被推断为int
而且accumulate
将总是返回一个int
。
如果使用C ++ 14就可以了,你可以用你的神秘类型代替auto
。
如果你只限于C ++ 11,你可以使用以下稍微丑陋的解决方案:
template<typename T>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method) ->
typename std::result_of<decltype(method)(MyClass*)>::type
{
return std::accumulate(vec.begin(), vec.end(), 0,
[&](typename std::result_of<decltype(method)(MyClass*)>::type acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
这为您提供了在MyClass*
上调用method
的结果所具有的类型。
顺便说一下,实际上没有必要在呼叫站点使用bind
。 您可以使用lambda实现相同的功能:
ACCUMULATE_ON_VECTOR(_myVec, [] (const MyClass* p) { return p->someMethod(); });
(在C ++ 14,你可以替换const MyClass*
与auto
,如果你想)
累积的结果类型与传递的累积函数无关。 累积的结果类型是第三个参数的类型。 你得到警告,因为你的第三个参数是0
(这是int)所以int64
将被截断为int
! 您应该传递int46(0)
作为无警告代码的第三个参数。
你可以使用std::iterator_traits
template<typename T>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
-> typename std::iterator_traits<T(MyClass*)>::value_type
{
return std::accumulate(
vec.begin(),
vec.end(),
0,
[&](typename std::iterator_traits<T(MyClass*)>::value_type acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
}
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.