将模板typedef的数组传递给构造函数

时间:2011-07-22 23:15:41

标签: c++ arrays templates constructor containers

我在头文件中有一个模板类无法编译,但是当我尝试制作一个最小的展示案例时,它编译得很好。我正在尝试创建一个可以从数组构造的类,自动推导出长度。错误是“引用零大小的数组是非法的”,这是没有意义的,因为它应该通过模板自动推断出长度。
相关代码:

template<class _Elem, bool _Null=true, bool _Trunc=false, class _Traits = std::char_traits<char>>
class basic_estring {
public:
    typedef typename _Traits::pos_type size_type;
    typedef typename _Elem value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type &reference;
    typedef const value_type &const_reference;
    static const size_type npos;

    basic_estring(const_pointer ptr, size_type capacity=npos, size_type used=npos);
    template<int capacity> basic_estring(value_type (&data)[capacity], size_type used=npos);
    // several hundred lines of other declarations
};
template<class _Elem, bool _Null, bool _Trunc, class _Traits>
basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(
    typename basic_estring<_Elem,_Null,_Trunc,_Traits>::const_pointer ptr, 
    typename basic_estring<_Elem,_Null,_Trunc,_Traits>::size_type capacity, 
    typename basic_estring<_Elem,_Null,_Trunc,_Traits>::size_type used)
{} //This constructor has no problems (and all the others too)

template<class _Elem, bool _Null, bool _Trunc, class _Traits> template<int capacity> 
basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(
    typename basic_estring<_Elem,_Null,_Trunc,_Traits>::value_type (&data)[capacity], //LINE 218
    typename basic_estring<_Elem,_Null,_Trunc,_Traits>::size_type used)
{} //LINE 228
//several hundred lines of definitions

来自MSVC C ++ 2010的错误:

1>/*snip*/\estring.h(218): error C2265: 'abstract declarator' : reference to a zero-sized array is illegal
1>/*snip*/\estring.h(228): error C2244: 'basic_estring<_Elem,_Null,_Trunc,_Traits>::{ctor}' : unable to match function definition to an existing declaration
1>  definition
1>  'basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring<_Elem,_Null,_Trunc,_Traits>::value_type (&)[1],basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring<_Elem,_Null,_Trunc,_Traits>::size_type)'
1>  existing declarations
1>  'basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(const basic_estring<_Elem,_Null,_Trunc,_Traits> &&)'
1>  'basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(const basic_estring<_Elem,_Null,_Trunc,_Traits> &)'
1>  'basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(const std::basic_string<_Elem,_Traits,Alloc> &)'
1>  'basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(_Elem (&)[capacity],_Traits::pos_type)'
1>  'basic_estring<_Elem,_Null,_Trunc,_Traits>::basic_estring(const _Elem *,_Traits::pos_type,_Traits::pos_type)'

任何人都知道我做错了什么?我通常很善于解决自己的问题,但这让我很难过。我从其他构造函数中重写了它,并没有解决任何问题 [编辑]当此项目中的非原型代码

时,错误仍然存​​在
int main() {
    return 0;
}

(包括没有函数定义)因此,据我所知,它不是实例化问题。当我评论这段代码的时候,我一直在评论类内部的代码,并发现如果我注释掉了成员函数原型capacity,那么错误就会消失。我的班级不继承任何其他班级。

void resize( size_type Count );
void resize( size_type Count, value_type Ch );
size_type capacity( ) const;  //if this is commented, the error goes away.
void reserve( size_type Count );

现在我完全难过了。 [/编辑]

2 个答案:

答案 0 :(得分:1)

在您的代码中,您传递的是一个零大小的数组作为构造函数的参数,导致编译器尝试为匹配的basic_estring构造函数签名实例化模板,该签名将定义{{ 1}}作为capacity,然后将对零大小数组的引用传递给构造函数。换句话说,问题不是构造函数声明,而是代码中的其他地方,您尝试实例化特定版本的构造函数模板。

例如,这段代码编译得很好:

0

另一方面,将#include <iostream> template<typename T> class A { T* array; public: template<int capacity> A(T (&data)[capacity]) { std::cout << capacity << std::endl; } }; int main() { int array[5]; A<int> b(array); return 0; } 的声明更改为

array

不再编译。它无法从输入参数中推导出int main() { int array[] = {}; A<int> b(array); return 0; } 的模板值。实际上,capacity似乎无法正确识别参数类型,因为错误是

gcc

意味着prog.cpp: In function ‘int main()’: prog.cpp:22: error: no matching function for call to ‘A<int>::A(int [0])’ prog.cpp:5: note: candidates are: A<int>::A(const A<int>&) 正在寻找可用于类型转换的某种类型的单参数构造函数,默认的编译器创建的复制构造函数是唯一可用的候选者,因为我从未声明任何其他构造函数参数。

因此,您的构造函数模板声明/定义本身很好,但如果您使用零长度数组实例化它,则参数类型不正确,并且无法正确实例化模板。我要查找错误的第一个地方是你的gcc被实例化,而不是想知道构造函数本身有什么问题。

答案 1 :(得分:1)

我终于明白了。当类还具有成员函数capacity时,模板类型为capacity的构造函数失败。哎呦。当我将模板类型重命名为Cap

时,问题就消失了