模板,类型扣除不足

时间:2015-08-28 16:40:31

标签: c++ templates template-deduction

我正在使用StreamsàlaJava 8的实现。我更喜欢编译器接受以下代码

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 个答案:

答案 0 :(得分:4)

lambda不是std::function,你几乎从不想要使用std::function</* something that contains a template parameter */>作为函数模板的参数,因为模板参数的唯一方法就是推导出来的是调用者是否构造了一个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