我试图让Slice模板类使用基于范围的for()(在带有auto的for()行上时,在gcc 4.6.1中得到以下编译错误:
我做错了什么?
sandbox.cpp:31:17:错误:无法将
‘(& t)->Slice<T>::Begin [with T = int, typename std::vector<_RealType>::const_iterator = __gnu_cxx::__normal_iterator<const int*, std::vector<int> >]()’
从‘const const_iterator {aka const __gnu_cxx::__normal_iterator<const int*, std::vector<int> >}’
转换为‘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:在函数
中‘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;
}
答案 0 :(得分:3)
您的begin
和end
模板参数设置错误。它们被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
。你的工作量较少。