使用基于范围的for()编译Slice模板失败

C++0x: Slice template fails to compile with range-based for()

本文关键字:Slice 编译 失败 for 于范围 范围      更新时间:2023-10-16

在gcc 4.6.1中,当试图让Slice模板类与基于范围的for()一起工作时,我得到以下编译错误(发生在for()行与auto):

  1. 我知道在boost中有一个slice类-这只是为了说明目的
  2. 我设法让基于范围的for()与普通类一起工作-只是有模板类的问题。

我做错了什么?

sandbox.cpp:31:17: error: could not convert ‘(& t)->Slice<T>::Begin [with T = int, typename std::vector<_RealType>::const_iterator = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >]()’ from ‘const const_iterator {aka const __gnu_cxx::__normal_iterator<const int*, std::vector<int> >}’ to ‘std::vector<Slice<int>, std::allocator<Slice<int> > >::const_iterator {aka __gnu_cxx::__normal_iterator<const Slice<int>*, std::vector<Slice<int>, std::allocator<Slice<int> > > >}’

sandbox.cpp: In function ‘typename std::vector<_RealType>::const_iterator end(const T&) [with T = Slice<int>, typename std::vector<_RealType>::const_iterator = __gnu_cxx::__normal_iterator<const Slice<int>*, std::vector<Slice<int>, std::allocator<Slice<int> > > >]’

代码:

#include <vector>
#include <algorithm>
using namespace std;
template< typename T >
class Slice 
{
public:
    Slice( const vector< T >& v,
        typename vector< T >::const_iterator it0, 
        typename vector< T >::const_iterator itEnd ) :
        m_v( v ), m_it0( it0 ), m_itEnd( itEnd )
    { }
public:
    const typename vector<T>::const_iterator Begin() const
        { return m_it0;     }
    const typename vector<T>::const_iterator End()   const
        { return m_itEnd; }
private:
    const vector< T >&                         m_v;
    const typename vector< T >::const_iterator m_it0, m_itEnd;
};
template< typename T >
typename vector<T>::const_iterator
begin( const T& t )
{
    return t.Begin();
}
template< typename T >
typename vector<T>::const_iterator
end( const T& t )
{
    return t.End();
}
int main(int argc, char** argv)
{
    vector<int> v = { 1, 2, 3, 4, 5, 6 };
    Slice<int>  s( v, v.begin()++, v.end() );
    for( auto x : s ) 
    {
    }
    return 0;
}

您的beginend模板参数设置错误。它们被传递给s,即Slice<int>,因此T被推导为Slice<int>。返回类型是vector<Slice<int> >::const_iterator。但是Slice<int>::Begin返回vector<int>::const_iterator

正如你在评论中提到的,解决方案是将参数从const T&更改为const Slice<T>&。这样,T被演绎为int而不是Slice<int>,返回类型变为vector<int>::const_iterator

template<typename T>
typename std::vector<T>::const_iterator
begin(const Slice<T>& s) {
  return s.Begin();
}

但是,如果您将函数的名称更改为begin而不是Begin,则可以使用std::begin,它具有更通用的行为:

template<typename T>
auto begin(const T& t) 
-> decltype(t.begin()) {
  return t.begin();
}

基于范围的for语句有一个特殊的规则,确保即使您的类型不是命名空间std的一部分,也能通过依赖参数的查找找到std::begin