【问题标题】:C++ cast from back_insert_iterator to iterator within functorsC++ 从 back_insert_iterator 转换为仿函数内的迭代器
【发布时间】:2012-09-13 22:53:17
【问题描述】:

我有点尝试实现一种复制运算符。 目的是有两个类:一个浏览容器,一个用它做一些事情。 Browse 类还(出于某种原因)在输出容器上维护一个迭代器,另一个可以用它计算增量。

不幸的是,编译器似乎无法将 back_insert_iterator 转换为输出迭代器。为什么?

#include <iostream>
#include <iterator>
#include <vector>

typedef std::vector<int> Vec;

// An operator that copy an item onto another
template< class TIN, class TOUT >
class DoCopy
{
    TOUT operator()( const typename TIN::iterator i_in, const typename TOUT::iterator i_out )
    {
        const typename TOUT::iterator i_incr = i_out;
        (*i_incr) = (*i_in);
        std::advance( i_incr, 1 );
        return i_incr;
    }
};

// The class that iterate over a container, calling an operator for each item
template< class TIN, class TOUT >
class Browse
{
    public:
        // We keep a reference to the operator that really do the job
        DoCopy<TIN,TOUT> & _do;
        Browse( DoCopy<TIN,TOUT> & op ) : _do(op) {}

        // Iterate over an input container
        TOUT operator()(
                const typename TIN::iterator in_start,
                const typename TIN::iterator in_end,
                const typename TOUT::iterator out_start
            )
        {
            TOUT i_out = out_start;

            for( TIN i_in = in_start; i_in != in_end; ++i_in ) {
                // it is not shown why here, but we DO want the operator to increment i_out
                i_out = _do(i_in, i_out);
            }
        }
};

int main()
{
    // in & out could be the same type or a different one
    Vec in;
    Vec out;
    DoCopy<Vec,Vec> do_copy;
    Browse<Vec,Vec> copy(do_copy);

    std::back_insert_iterator< Vec > insert_back(out);

    // Here, g++ cannot find the corresponding function :
    copy( in.begin(), in.end(), insert_back );

}

g++ 编译失败,出现以下错误:

$ g++ test.cpp && ./a.out
    test.cpp: In function ‘int main()’:
    test.cpp:54:49: erreur: no match for call to ‘(Browse<std::vector<int>, std::vector<int> >) (std::vector<int>::iterator, std::vector<int>::iterator, std::back_insert_iterator<std::vector<int> >&)’
    test.cpp:22:11: note: candidate is:
    test.cpp:30:18: note: TOUT Browse<TIN, TOUT>::operator()(typename TIN::iterator, typename TIN::iterator, typename TOUT::iterator) [with TIN = std::vector<int>, TOUT = std::vector<int>, typename TIN::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >, typename TOUT::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]
    test.cpp:30:18: note:   no known conversion for argument 3 from ‘std::back_insert_iterator<std::vector<int> >’ to ‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’

【问题讨论】:

  • std::copy有什么问题吗?
  • 我其实是在尝试实现别的东西,但是选择副本的例子,因为我认为它会更清楚地说明问题。
  • 调用你的变量copy是邪恶的。此外,您在整个代码中使用 const 很奇怪,很可能是您的问题的原因。
  • copy 定义在std&lt;algorithm&gt; 中,此处不包含。我看不出在一个为了解释而伪造的简单示例中使用它是多么邪恶。你说的“奇怪”是什么意思?任何解决我的问题的提示将不胜感激:-)
  • @nojhan:将函数的参数设置为const T 真是太奇怪了。这让我觉得你的意思是 const T&amp; 或者是要传递 const 迭代器,但搞砸了。此外,您也将i_incr 声明为const,这是错误的,因为您实际上是在修改它。 (另外,你正在写它,所以你也不会想到const_iterator

标签: c++ iterator


【解决方案1】:

这是问题的主要根源:std::back_insert_iterator&lt; V&lt;T&gt; &gt;std::vector&lt;T&gt;::iterator 在它们的继承树中没有直接关系:

  • std::vector&lt;T&gt;::iterator__normal_iterator&lt;T&gt;(没有其他超类)(查看 stl_vector.h 对应 std::vector&lt;T&gt;::iteratorstl_iterator.h 对应 __normal_iterator
  • std::back_insert_iterator&lt; V&lt;T&gt; &gt; 是一个迭代器(没有其他超类)(请查看 stl_iterator.h 以获取 std::back_insert_iteratorstl_iterator_base_types.h 以获取 std::iterator)。

它们不能向任何方向转换。

因此,第二个模板参数应该直接是std::back_insert_iteratoriterator&lt;&gt;,并带有好的第一个参数表明这是一个输出运算符。

std::advance( iterator, 1 ),我假设您的意思是 ++iterator,这是为迭代器转到下一个元素的标准方法。

此外,out迭代器不应该是const,否则他们不会实现operator=的做作。

第 38 行,i_in 的类型应为 typename TIN::iterator 而不是 TIN。 Browse operator() 还必须返回 out 迭代器。

最终代码如下所示:

#include <iostream>
#include <iterator>
#include <vector>

typedef std::vector<int> Vec;

// An operator that copy an item onto another
template< class TIN, class TOUT >
class DoCopy
{
    public:

    TOUT operator()( const typename TIN::iterator i_in, const TOUT i_out )
    {
        TOUT i_incr = i_out;
        (*i_incr) = (*i_in);
        //std::advance( i_incr, 1 );
        ++i_incr;
        return i_incr;
    }
};

// The class that iterate over a container, calling an operator for each item
template< class TIN, class TOUT >
class Browse
{
    public:
        // We keep a reference to the operator that really do the job
        DoCopy<TIN,TOUT> & _do;
        Browse( DoCopy<TIN,TOUT> & op ) : _do(op) {}

        // Iterate over an input container
        TOUT operator()(
                const typename TIN::iterator in_start,
                const typename TIN::iterator in_end,
                const TOUT out_start
            )
        {
            TOUT i_out = out_start;

            for( typename TIN::iterator i_in = in_start; i_in != in_end; ++i_in ) {
                // it is not shown why here, but we DO want the operator to increment i_out
                i_out = _do(i_in, i_out);
            }
            return i_out;
        }
};

int main()
{
    // in & out could be the same type or a different one
    Vec in;

    in.push_back(1);
    in.push_back(3);
    in.push_back(3);
    in.push_back(7);

    Vec out;
    DoCopy<Vec, std::back_insert_iterator<Vec> > do_copy;
    Browse<Vec, std::back_insert_iterator<Vec> > copy(do_copy);

    std::back_insert_iterator< Vec > insert_back(out);

    // Here, g++ cannot find the corresponding function :
    copy( in.begin(), in.end(), insert_back );

    for( unsigned i = 0, s = out.size(); i < s; ++i )
    {
        std::cout << out[i] << " ";
    }
    std::cout << std::endl;
}

感谢clang++,它让 C++ 错误更加清晰。

【讨论】:

  • std::advance(i,1) 等价于i++。在我的应用程序中,我需要多次推进迭代器。
猜你喜欢
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-24
  • 2021-12-30
  • 2022-01-08
相关资源
最近更新 更多