模板,类型推导不足

3
我正在使用类似Java 8的Stream实现进行尝试。我希望编译器能够接受以下代码片段。
Stream stream;
stream
    .map      ([] (int x)  { return 10*x; })      // error
    .forEach  ([] (int x)  { cout << x << " ";}); 

但是编译器(gcc版本4.9.2)拒绝了它,并附有注释。
template argument deduction/substitution failed:
‘main(int, char**)::<lambda(int)>’ is not derived from ‘std::function<Re(int)>’
   .map       ([] (int x)  { return 10*x; })
requires a type parameter for `map`

它能够编译(并且运行良好)使用以下技术:

   .map<int>  ([] (int x)  { return 10*x; })

有没有希望摆脱那个 <map> 东西?


这里是精简的代码(已经声明足够)

#include <iostream>
#include <functional>

using namespace std;

template <typename Tfrom, typename Tto> class MappedStream;

template <typename T>
class Stream
{
  public:
    void forEach(function< void(T) > action) 
    {}

    template <typename Re>
    MappedStream<T,Re> map (function < Re(T)> mapping) {
        return MappedStream<T,Re>(*this, mapping);
    }
};

template <typename Tfrom, typename Tto>
class MappedStream
   : public Stream<Tto>
{   
  public:
    MappedStream(Stream<Tfrom> & source,
                function <Tto(Tfrom)> mapping)
    {}
};

int main(int argc, char **argv)
{   
  Stream<int> stream;
  stream
   .map<int> ([] (int x) { return 10*x; })
   //  XXXXX                          <- how to get rid of this?
   .forEach  ([] (int x) { cout << x << " ";});

   return 0;
}

1
你可以这样做(http://coliru.stacked-crooked.com/a/0dfd82ff3c7d075b),但我猜它会破坏你的设计(你似乎喜欢`std::function`)。 - Piotr Skotnicki
你无法从lambda推断出std::function - Jarod42
1个回答

4
一个 Lambda 不是一个 std::function,并且你几乎从来不想使用 std::function</* 带有模板参数的内容 */> 作为函数模板的参数,因为其中的模板参数唯一能被推断的方式是调用者构造一个 std::function 并传递它进去。
相反,接受任何函数对象,然后找出返回类型:
template <typename F, typename Re = std::result_of_t<F&(T)>>
MappedStream<T,Re> map (F mapping) {
    return MappedStream<T,Re>(*this, mapping);
}

通常情况下,应该避免不必要的类型擦除。对于MappedStream来说,它的类型不应该依赖于使用的映射器,因此在其中存储std::function是比较合理的。但是,forEach可能应该是一个模板,接受任何函数对象,而不仅仅是std::function。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接