繁体   English   中英

如何推导std :: bind对象的返回类型以供模板使用?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM