2014-10-30 11 views
9

aşağıdaki şablona sahip değil.Derleyici, şablon parametrelerini (map std :: vector -> std :: vector)

template<typename T, typename U> 
std::vector<U> map(const std::vector<T> &v, std::function<U(const T&)> f) { 
    std::vector<U> res; 
    res.reserve(v.size()); 
    std::transform(std::begin(v), std::end(v), std::end(res), f); 
    return res; 
} 

Kodumda kullandığımda, şablon parametrelerini belirtmem gerekir. Derleyici neden benim için bunu anlayamıyor? Bu çalışmayı yapmak için şablon tanımımı nasıl değiştirmeliyim?

vector<int> numbers = { 1, 3, 5 }; 

// vector<string> strings = map(numbers, [] (int x) { return string(x,'X'); }); 

vector<string> strings = map<int, string>(numbers, [] (int x) { return string(x,'X'); }); 

Runnable kodu: http://ideone.com/FjGnxd

bu soruya orijinal kod buradan geliyor: The std::transform-like function that returns transformed container

cevap

17

İşleviniz bir std::function argümanlar bekler, ancak bunun yerine bir lambda ifadesi ile diyoruz. İkisi de aynı tip değil. Bir lambda dönüştürülebilir - std::function, ancak şablon argümanı indirimi tam eşlemeler gerektirir ve kullanıcı tanımlı dönüşümler dikkate alınmaz. Dolayısıyla kesinti başarısızlığı.

Kesinti, std::function için map()'a iletirseniz çalışır.

std::function<string(int const&)> fn = [] (int x) { return string(x,'X'); }; 
vector<string> strings = map(numbers, fn); 

Live demo


olası bir çözüm şablon bağımsız değişkenleri belirlemek zorunda kalmamak için çağrılabilir herhangi bir yerine, bir std::function nesnesi kabul işlevi değiştirmek için. bir arka dönüş türü

template<typename T, typename Func> 
auto map(const std::vector<T> &v, Func f) 
    -> std::vector<decltype(f(v[0]))> { 
     // ... 
    } 
Genellikle

Live demo

+0

kullanılarak

template<typename T, typename Func> std::vector<decltype(std::declval<Func>()(std::declval<T>()))> map(const std::vector<T> &v, Func f) { // ... } 

Son olarak decltype ve declval yerine result_of kullanılarak

template<typename T, typename Func> std::vector<typename std::result_of<Func(T)>::type> map(const std::vector<T> &v, Func f) { // ... } 

aynı fikri bir başka versiyonu, 'typename std :: sonuç_0 :: type', 'map' işlevinin içinde birden çok yerde görünür. Bunu daha kısa yapmak için yazamazsınız, ancak bunun için bir takma ad oluşturmanın bir yolu vardır, böylece tekrarlama olmaz mı? – Ferenc

+1

@Ferenc C++ 14'e sahipseniz, std :: result_of_t 'şeklinde kısaltılabilir. Veya kendi şablonunuzu yazarak result_of_t = typename result_of :: type; – Praetorian