【问题标题】:Passing array of template typedef's to constructor将模板类型定义数组传递给构造函数
【发布时间】:2011-07-22 23:15:40
【问题描述】:

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

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 );

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

【问题讨论】:

  • 首先,您应该避免在符号前加上下划线,除非您真的知道自己在做什么。见:stackoverflow.com/questions/228783
  • 第二,你有没有尝试在类内部内联构造函数,看看会发生什么?
  • 你能显示调用代码吗?最小示例的问题是,如果不使用模板类中的函数,它们甚至不会被实例化,因此您可能会遗漏错误。尝试让您的最小示例使用所有类成员函数。
  • @paercebal 我复制了一些 std::basic_string 的功能,所以我也复制了很多参数名称。我已经删除了下划线。
  • @Kerrek SB,还没有调用代码,除非它在此类的成员函数定义之一中。不过我找不到类似的东西。

标签: c++ arrays templates constructor containers


【解决方案1】:

您的代码中似乎某处您正在将一个大小为零的数组作为参数传递给您的构造函数,导致编译器尝试为匹配的 basic_estring 构造函数签名实例化一个模板,该签名将 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 正在寻找某种类型的可用于类型转换的单参数构造函数,默认编译器创建的复制构造函数是唯一可用的候选者,因为我从未声明任何其他带有单参数的构造函数。

所以你的构造函数模板声明/定义本身没问题,但是如果你用零长度数组实例化它,那么参数类型不正确,模板不能被正确实例化。我要查找您的错误的第一个地方是您的 basic_estring 被实例化的位置,而不是想知道构造函数本身有什么问题。

【讨论】:

  • 这也是我的第一个想法。我注释掉了所有不属于该类的代码,但错误仍然存​​在。但是,我刚刚发现如果我注释掉 capacity() 原型,错误就会消失。
【解决方案2】:

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

时,问题就消失了

【讨论】:

  • 很高兴你能抓住它...... +1
猜你喜欢
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
  • 1970-01-01
  • 2012-12-06
  • 2011-10-24
相关资源
最近更新 更多