【发布时间】:2010-10-03 02:51:51
【问题描述】:
当我尝试将固定大小的数组传递给模板函数时,我的编译器行为异常。代码如下:
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename TSize, TSize N>
void f(TSize (& array)[N]) {
std::copy(array, array + N, std::ostream_iterator<TSize>(std::cout, " "));
std::cout << std::endl;
}
int main() {
int x[] = { 1, 2, 3, 4, 5 };
unsigned int y[] = { 1, 2, 3, 4, 5 };
f(x);
f(y); //line 15 (see the error message)
}
它在 GCC 4.1.2 中产生以下编译错误:
test.cpp|15| error: size of array has non-integral type ‘TSize’ test.cpp|15| error: invalid initialization of reference of type ‘unsigned int (&)[1]’ from expression of type ‘unsigned int [5]’ test.cpp|6| error: in passing argument 1 of ‘void f(TSize (&)[N]) [with TSize = unsigned int, TSize N = ((TSize)5)]’
请注意,第一次调用编译并成功。这似乎暗示虽然int 是不可或缺的,但unsigned int 不是。
但是,如果我将上述函数模板的声明更改为
template <typename TSize, unsigned int N>
void f(TSize (& array)[N])
问题就解决了!请注意,这里唯一的变化是从 TSize N 到 unsigned int N。
最终草案 ISO/IEC FDIS 14882:1998 中的 [dcl.type.simple] 部分似乎暗示“整数类型”是有符号或无符号的:
signed说明符强制char对象和位域被签名;它与其他整数类型是多余的。
关于固定大小的数组声明,草案说 [dcl.array]:
如果constant-expression (
expr.const) 存在,它应该是一个整数常量表达式,并且它的值应该大于零。
那么,为什么我的代码可以使用显式的 unsigned 尺寸类型、推断的 signed 尺寸类型但不能使用推断的 unsigned 尺寸类型?
编辑 Serge 想知道我在哪里需要第一个版本。首先,这个代码示例显然被简化了。我的真实代码要复杂一些。该数组实际上是另一个数组中的索引/偏移量数组。 因此,从逻辑上讲,数组的类型应该与其大小类型相同,以获得最大的正确性。 否则,我可能会得到类型不匹配(例如,unsigned int 和 std::size_t 之间)。诚然,这在实践中应该不是问题,因为编译器会隐式转换为两种类型中较大的一种。
编辑 2 我已得到纠正(谢谢,litb):大小和偏移量当然在逻辑上是不同的类型,尤其是 C 数组的偏移量是 std::ptrdiff_t 类型。
【问题讨论】:
-
第一个示例使用 Microsoft 编译器 (2005) 编译得很好。 Digital Mars 在“void f(TSize (& array)[N]) {”行中抱怨“错误:预期的积分表达式”
-
你能举个例子,你绝对必须使用第一个版本吗?
-
在关于基本类型的析构函数的线程中被确认不能直接调用~int,而是在模板中执行 typedef int MyType;调用 ~MyType 是合法的。但我认为正确的做法是使用 size_t 作为第二个参数。
-
这绝对是有趣的康拉德。至少,comeau 接受该代码。
-
Serge,litb,请将您的 cmets 变成答案,以便其他人可以更快地找到它们(因为我认为它们是相关的)。 @xhantt:我不确定析构函数与此有什么关系。在我的函数中,任何地方都不应调用
TSize的构造函数(甚至是隐式调用)。
标签: c++ arrays templates type-inference