c++ - 为什么 Clang 不喜欢 boost::transform_iterator?

标签 c++ c++11 boost clang

使用 Clang 8.0.1 和 Boost 1.70,以下程序

// transform.cpp
#include <vector>
#include <algorithm>
#include <iostream>

#include <boost/iterator/transform_iterator.hpp>

struct Foo
{
    int x;
};

struct XGetter
{
    auto operator()(const Foo& foo) const noexcept { return foo.x; }
};

int main()
{
    const std::vector<Foo> foos {{1}, {2}, {3}};
    using boost::make_transform_iterator;
    const auto first = make_transform_iterator(foos.cbegin(), XGetter {});
    const auto last = make_transform_iterator(foos.cend(), XGetter {});
    std::cout << *std::max_element(first, last) << std::endl;
}

编译失败

$ clang++ -std=c++14 -o transform transform.cpp

/usr/local/Cellar/llvm/8.0.1/bin/../include/c++/v1/algorithm:2494:5: error: static_assert failed due to requirement
      '__is_forward_iterator<boost::iterators::transform_iterator<XGetter, std::__1::__wrap_iter<const Foo *>,
      boost::use_default, boost::use_default> >::value' "std::max_element requires a ForwardIterator"
    static_assert(__is_forward_iterator<_ForwardIterator>::value,
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/Cellar/llvm/8.0.1/bin/../include/c++/v1/algorithm:2512:19: note: in instantiation of function template
      specialization 'std::__1::max_element<boost::iterators::transform_iterator<XGetter, std::__1::__wrap_iter<const
      Foo *>, boost::use_default, boost::use_default>, std::__1::__less<int, int> >' requested here
    return _VSTD::max_element(__first, __last,
                  ^
transform.cpp:24:24: note: in instantiation of function template specialization
      'std::__1::max_element<boost::iterators::transform_iterator<XGetter, std::__1::__wrap_iter<const Foo *>,
      boost::use_default, boost::use_default> >' requested here
    std::cout << *std::max_element(first, last) << std::endl;
                       ^
1 error generated.

我的印象是boost::transform_iterator继承了它建模的迭代器的迭代器类别。出了什么问题?

最佳答案

(C++20 之前的)标准需要前向或更强的迭代器:

  • 在解除引用时产生一个真正的引用;
  • 当两个相等的迭代器被解除引用时(即没有存储)产生对同一个对象的引用

由于您的转换按值返回,transform_iterator 无法同时满足这两个要求。因此,它只能将自己宣传为输入迭代器。

修复方法是将 XGetter 更改为通过引用返回,或者使用 std::mem_fn(&Foo::x) 为您完成此操作。

关于c++ - 为什么 Clang 不喜欢 boost::transform_iterator?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57596150/

相关文章:

c++ - 使用 cudaSetDeviceFlags 的正确位置?

c++ - Win32 DLL 没有返回正确的数据

c++ - 如何在初始化列表中创建一个非空的 boost ublas::vector?

boost - 如何在 asio::buffer() 中使用 std::string

c++ - 使用 Win32 C++ 检测文件句柄泄漏

c++ - 更改 Qt 访问的 Comport

c++ - 成对函数评估算法(C++、STL)

c++ - 为什么编译器不支持 c++11 thread_local 存储?

c++ - 编译器在移动构造函数和复制构造函数之间的选择

STL 或 boost 中的 C++ range/xrange 等价物?