c++ - C++ 中 std::reference_wrapper 和类型的编译器错误

标签 c++ types stl reference constants

我最近一直在深入研究 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;
}

这样就可以了。但是如果我创建一个简单的方法来消除手动复制 vector 的需要,就像这样

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 &'

我很困惑,因为我认为他们应该做同样的事情。如果我错了,有人可以指出我正确的方向。

附注我正在使用 Visual Studio 2015

更新:添加了 const 约束以返回函数类型,以正确反射(reflect) *max_element 返回 const 键的事实。 (由@dyp建议)

最佳答案

这些问题与常量有关。最初,隐式转换存在问题

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

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

第一个是const因为std::map的 key 节点是 const - 防止 key 突变应确保树数据结构保持有效。

不允许这种隐式转换;这可能与 std::pair 中描述的问题有关在 Improving pair and tuple - N4387 .

快速解决方法是使用 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>>
//                                                       ^^^^^

Live demonstration

更好的解决方案可能是认识到 _2函数不需要vector ,但只有两个迭代器来创建一个新 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)。

Live demo

关于c++ - C++ 中 std::reference_wrapper 和类型的编译器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32533436/

相关文章:

flutter - 如何为子类属性提供与 Dart 中的父类(super class)不同的类型?

c++ - wstringstream 到 LPCWSTR

c++ - 将 std::map 的数据拆分为多个 std::vectors

c++ - MongoDb 总和聚合 C++

c++ - IDISPATCH::Invoke 调用方法失败,错误 0x80020005 类型不匹配

c++ - 是否可以使用 C++ 从二进制文件中逐位读取?

MySQL 截断 GROUP_CONCAT 函数的连接结果

haskell - GHC 7.8 中类型级别自然的行为

c++ - 从 CSV 读入模板 vector

C++ 操作模板对象