簡體   English   中英

C++ 中 std::reference_wrapper 和類型的編譯器錯誤

[英]Compiler error with std::reference_wrapper and types in C++

我最近一直在潛心研究 C++,並且一直在嘗試 STL。 我遇到了一個我似乎無法解決的問題。 我猜這與我不了解 C++ 如何推導類型有關,但我不確定。 這是有效的代碼

template <typename T>
auto most_frequent_element(const std::vector<std::reference_wrapper<T>> &vector) -> boost::optional<std::pair<const std::reference_wrapper<T>, size_t>> {
    if (vector.empty()) {
        return{};
    }
    std::map<std::reference_wrapper<T>, size_t> individual_counts = {};
    std::for_each(vector.begin(), vector.end(), [&individual_counts](auto &element) {
        auto result = individual_counts.emplace(element, 0);
        (*result.first).second++;
     });
    return *std::max_element(individual_counts.begin(), individual_counts.end(), [](auto &a, auto &b) {
        return a.second < b.second;
    });
}

這就是我的稱呼

auto main(int argc, char *argv[]) -> int {
    std::vector<char> test = { 'a', 'a', 'b', 'b', 'c'};
    auto result = most_frequent_element(std::vector<std::reference_wrapper<char>>(test.begin(), test.end()));
    if (result) {
        std::cout << (*result).first << " " << (*result).second << std::endl;
    }
    else {
        std::cout << "Empty input list." << std::endl;
    }
    return EXIT_SUCCESS;
}

所以這有效。 但是如果我創建一個簡單的方法來消除手動復制矢量的需要,就像這樣

template <typename T>
auto most_frequent_element_2(const std::vector<T> &vector) -> boost::optional<std::pair<const std::reference_wrapper<T>, size_t>> {
    most_frequent_element(std::vector<std::reference_wrapper<T>>(vector.begin(), vector.end()));
}

並像這樣稱呼它

auto main(int argc, char *argv[]) -> int {
    std::vector<char> test = { 'a', 'a', 'b', 'b', 'c'};
    auto result = most_frequent_element_2(test);
    if (result) {
        std::cout << (*result).first << " " << (*result).second << std::endl;
    }
    else {
        std::cout << "Empty input list." << std::endl;
    }
    return EXIT_SUCCESS;
}

我收到以下錯誤

Error C2664 'std::reference_wrapper<char>::reference_wrapper(std::reference_wrapper<char> &&)': cannot convert argument 1 from 'const char' to 'char &'

我很困惑,因為我怎么看他們應該做同樣的事情。 如果我錯了,有人可以指出我正確的方向。

PS我在Visual Studio 2015中工作

更新:添加了 const 約束以返回函數類型,以正確反映 *max_element 返回 const 鍵的事實。 (由@dyp 建議)

這些問題與常量有關。 最初,從隱式轉換存在問題

optional<pair<const reference_wrapper<T>, size_t>> // A

optional<pair<reference_wrapper<T>, size_t>> // B

第一個是const因為std::map節點的鍵是const - 防止鍵的突變應確保樹數據結構保持有效。

不允許這種隱式轉換; 這可能與 改進pairtuple - N4387中為std::pair描述的問題 有關

一個快速的解決方法是使用A作為返回類型,而不是B 或者,使用顯式轉換(命名對象的強制轉換或構造)。


與常量相關的第二個問題是

reference_wrapper<T>

不能用 a 初始化

T const&

就像T&不能從T const類型的左值表達式初始化一樣。 出現此問題是因為most_frequent_element_2函數通過const&獲取其參數,然后對beginend的調用產生const_iterator s。

一個快速而骯臟的解決方案是創建一個vector<reference_wrapper<T const>>代替:

most_frequent_element(std::vector<std::reference_wrapper<T const>>(vector.begin(), vector.end()));
//                                                         ^^^^^

然后將_2函數的返回類型調整為

boost::optional<std::pair<const std::reference_wrapper<T const>, size_t>>
//                                                       ^^^^^

現場演示

更好的解決方案可能是認識到_2函數不需要vector ,而只需要兩個迭代器來創建新向量。 (相同的論點適用於原始的most_frequent_element函數。)您可以將其寫為:

template <typename InIt,
          typename T = std::remove_reference_t<decltype(*std::declval<InIt&>())>>
auto most_frequent_element_2(InIt b, InIt e)
  -> boost::optional<std::pair<const std::reference_wrapper<T>, size_t>> {
    return most_frequent_element(std::vector<std::reference_wrapper<T>>(b, e));
}

我使用第二個(默認)模板參數只是為了方便(聲明中的typedef )。

現場演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM