2015-08-28 3 views
3

я играл с реализацией Streams порционное Java 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> thingy?


Вот сокращенный код (с достаточным декларациями)

#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') –

+0

Вы не можете вывести 'std :: function' из лямбда. – Jarod42

ответ

4

Лямбда не 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.

Смежные вопросы