2017-10-12 77 views
-2

我試圖編譯這段代碼,這應該打印矢量的總和,在2017年VS爲什麼在此摺疊實現中不能推導出模板參數?

#include <stdio.h> 
#include <functional> 
#include <vector> 
#include <iostream> 
template<typename F, typename T, typename K> 
//int fold(F fun, T acc, K v) get the same error below 
int fold(F fun, T acc, std::vector<K> v) 
{ 
    switch (v.empty()) 
    { 
    case true: return acc; 
    case false: return fold(fun, fun(*v.begin(), acc), { ++v.begin(), v.end() }); 
    } 
} 
int main() 
{ 
    std::vector<int> v = { 1, 2, 3, 4 }; 
    std::cout << fold([](int a, int b) {return a + b; }, 0, v); 
} 

它產生一個錯誤:

error C2783: 'int fold(F,T,std::vector<K,std::allocator<K>>)': could not deduce template argument for 'K'

爲什麼不能K推斷到intstd::vector<int>在這裏?如果我更換

template<typename F, typename T, typename K> 
int fold(F fun, T acc, std::vector<K> v) 

template<typename F, typename T> 
int fold(F fun, T acc, std::vector<int> v) 

那麼它編譯成功。

+1

你也不回在'情況下沒有過錯:'。打開編譯器警告,也許不要在布爾值上使用'switch'。 'if(v.empty())返回acc;'更具可讀性。 (或'return v.empty()?acc:fold(...') – Ryan

+0

另外,我不是C++專家,但是看起來它每次都複製向量的其餘部分?爲什麼不接受迭代器而不是向量,比如'std :: fill',例如你想要返回'T'而不是'int'。 – Ryan

+0

@RyanThanks你的建議,但是我實際上返回acc以防錯誤,你能解釋一下嗎? – czxyl

回答

2
{ ++v.begin(), v.end() } 

這被解釋爲兩個元素的初始化列表。採用初始化列表的構造函數被選中,而不是採用兩個迭代器的構造函數。結果,你試圖調用fold而不是使用原始矢量的縮小副本,而是使用兩個完全不同的元素的矢量。但累加器參數與它們不匹配,所以模板參數推導失敗。

要解決,有一個明確的建築取代這個:也

std:::vector<K> { ++v.begin(), v.end() } 

,在false情況下使用return fold (...)

2

另一種方式 - 支持每種容器。 (更新支持的元組)

#include <functional> 
#include <vector> 
#include <iostream> 
#include <initializer_list> 
#include <algorithm> 
#include <tuple> 
#include <array> 
#include <utility> 
#include <type_traits> 
#include <numeric> 

template<typename F, typename T, typename Container> 
auto fold(F fun, T acc, Container&& v) 
{ 
    using value_type = std::decay_t<decltype(*std::begin(v))>; 
    return std::accumulate(std::begin(v), std::end(v), value_type(acc), std::forward<F>(fun)); 
} 

// spceial case for initializer_list as it can't be deduced from a braced initializer 
template<typename F, typename T, class V> 
auto fold(F fun, T acc, std::initializer_list<V> v) 
{ 
    using value_type = std::decay_t<decltype(*std::begin(v))>; 
    return std::accumulate(std::begin(v), std::end(v), value_type(acc), std::forward<F>(fun)); 
} 

template<typename F, typename T, class Tuple, std::size_t...Is> 
auto fold_tuple(F&& f, T acc, Tuple&& tuple, std::index_sequence<Is...>) 
{ 
    using expand = int[]; 
    void(expand{ 
     0, 
     (acc = f(acc, std::get<Is>(std::forward<Tuple>(tuple))), 0)...   
    }); 
    return acc; 
} 

template<typename F, typename T, class...Vs> 
auto fold(F&& f, T acc, std::tuple<Vs...> const& tuple) 
{ 
    using value_type = std::common_type_t<std::decay_t<Vs>...>; 
    using tuple_type = std::tuple<Vs...>; 
    constexpr auto element_count = std::tuple_size_v<tuple_type>; 
    return fold_tuple(std::forward<F>(f), value_type(acc), tuple, std::make_index_sequence<element_count>()); 
} 

template<typename F, typename T, class...Vs> 
auto fold(F&& f, T acc, std::tuple<Vs...> && tuple) 
{ 
    using value_type = std::common_type_t<std::decay_t<Vs>...>; 
    using tuple_type = std::tuple<Vs...>; 
    constexpr auto element_count = std::tuple_size_v<tuple_type>; 
    return fold_tuple(std::forward<F>(f), value_type(acc), std::move(tuple), std::make_index_sequence<element_count>()); 
} 

int main() 
{ 
    std::vector<int> v = { 1, 2, 3, 4 }; 
    std::cout << fold(std::plus<>(), 0, v) << std::endl; 

    std::cout << fold(std::plus<>(), 0, { 2, 4, 6, 8 }) << std::endl; 

    std::cout << fold(std::plus<>(), 0, std::array<double, 4>{ 2.1, 4.1, 6.1, 8.1 }) << std::endl; 

    const double xx[] = { 1, 2, 3, 4, 5.5 }; 
    std::cout << fold(std::plus<>(), 0, xx) << std::endl; 

    std::cout << fold(std::plus<>(), 0, std::make_tuple(1, 2, 3, 4, 5.5)) << std::endl; 

    int x = 6; 
    double y = 7.7; 
    long long z = 100; 

    std::cout << fold(std::plus<>(), 0, std::tie(x, y, z)) << std::endl; 

} 

預期輸出:

10 
20 
20.4 
15.5 
15.5 
113.7 

http://coliru.stacked-crooked.com/a/2eb9df5e4f60258e

相關問題