如何将数组的大小通过与模板类型的模板? [英] How to pass an array size as a template with template type?
问题描述
我的编译器的行为很奇怪,当我尝试到一个固定大小的数组传递给一个模板函数。在code如下所示:
的#include<&算法GT;
#包括LT&;&iostream的GT;
#包括LT&;&迭代器GT;模板< typename的TSIZE,TSIZE N'GT;
空隙F(TSIZE(安培;阵列)[N]){
性病::复制(数组,数组+ N的std :: ostream_iterator<&TSIZE GT;(STD ::法院));
性病::法院LT&;<的std :: ENDL;
}诠释主(){
INT X [] = {1,2,3,4,5};
无符号整型Y [] = {1,2,3,4,5};
F(X);
F(y)基// 15行(看到错误消息)
}
这将产生以下编译错误在GCC 4.1.2:
TEST.CPP | 15 |错误:数组的大小非整体式TSIZE
TEST.CPP | 15 |错误:类型的引用无效初始化
无符号整数(安培)[1]从$恩式的对$ pssion无符号整型[5]
TEST.CPP | 6 |错误:传递参数1'无效F(TSIZE(安培)[N])
[与TSIZE = unsigned int类型,TSIZE N =((TSIZE)5)'
块引用>需要注意的是在第一次调用编译和成功。这似乎意味着,尽管
INT
是不可或缺的,unsigned int类型
不是但是,如果我改变上述函数模板的声明
模板< typename的TSIZE,无符号整型N'GT;
无效F(TSIZE(安培;数组)[N])问题只是消失!请注意,这里唯一的变化是从
TSIZEñ
到无符号整数ñ
。第[<$ C $ C> dcl.type.simple ]在最后的草案ISO / IEC FDIS 14882:1998似乎暗示着一个整体式的符号或符号:
的
签署
符力字符
对象和位字段签署;它是多余的与其他整数类型。
块引用>对于固定大小的数组声明草案说,[
dcl.array
]:
如果在恒前pression 的(
expr.const
)是present,它应是整型常量前pression其值应大于零。
块引用>那么,为什么我有一个明确的
无符号
尺寸型code工作,推断签署
尺寸类型,但不与推断无符号
尺寸类型?修改塞尔想知道我需要的第一个版本。首先,code例子明显简化。我真正的code是更复杂一点。数组实际上是指数/偏移的另一个数组的数组。
因此,从逻辑上讲,数组的类型应该是一样的大小类型最大的正确性。否则,我可能会得到一个类型不匹配(例如之间unsigned int类型
和的std ::为size_t
)。诚然,因为编译器隐式转换这不应该在实践中的问题的两种类型的较大的编辑2 我认错(感谢,litb):尺寸和偏移量是当然的逻辑不同的类型,并偏移到尤其是C数组类型
的std ::的ptrdiff_t的
。解决方案嗯,标准说,在
14.8.2.4 / 15
:
如果,在与非类型模板参数函数模板的声明,非类型模板参数在功能参数列表的当然pression使用,并且,如果相应的模板 - 参数推导出模板参数的类型必须完全匹配模板参数的类型,除了从绑定一个数组推导出一个模板参数可以是任何整数类型。的
块引用>提供了这个例子:
模板&LT; INT I&GT; A级{/ * ... * /};
模板&LT;短S&GT;无效F(A&LT; S&GT;);
空隙K1(){
A&LT; 1 GT;一个;
F(一); //错误:转换无法扣除从int到短
F&所述1为卤素;(一); // 好
}这意味着失败的编译器来编译code(GCC显然和数字火星)这样做是错误的。我测试了code。与科莫,并将其编译你的code罚款。我不认为这是对非类型模板参数的类型是否取决于类型参数与否的类型不同。
14.8.2.4/2
表示模板参数应相互推导出独立的,然后组合成函数参数的类型。与/ 15,这使得维的类型是不同整型的结合起来,我觉得你的code是所有罚款。与往常一样,我拿C ++ - 是 - 复杂那么我-可能待卡错:)更新:我看着在GCC的推移它吐出的错误消息:
...
类型= TREE_TYPE(大小);
/ *绑定必须是整数类型的阵列。 * /
如果(dependent_type_p(类型)及!&放大器;!INTEGRAL_TYPE_P(类型))
{
如果(姓名)
错误(数组%qD的大小具有非整数类型%qT,名称,类型);
其他
错误(数组的大小的非整数类型%qT型);
大小= integer_one_node;
类型= TREE_TYPE(大小);
}
...这似乎已经错过了标记的大小取决于在更早的code座的类型。由于该类型是一个模板参数,它是一种依赖型(见
14.6.2.1
)。更新: GCC开发者固定它:错误#38950
My compiler behaves oddly when I try to pass a fixed-size array to a template function. The code looks as follows:
#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) }
It produces the following compile error in 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)]’
Note that the first call compiles and succeeds. This seems to imply that while
int
is integral,unsigned int
isn't.However, if I change the declaration of my above function template to
template <typename TSize, unsigned int N> void f(TSize (& array)[N])
the problem just goes away! Notice that the only change here is from
TSize N
tounsigned int N
.Section [
dcl.type.simple
] in the final draft ISO/IEC FDIS 14882:1998 seems to imply that an "integral type" is either signed or unsigned:The
signed
specifier forceschar
objects and bit-fields to be signed; it is redundant with other integral types.Regarding fixed-size array declarations, the draft says [
dcl.array
]:If the constant-expression (
expr.const
) is present, it shall be an integral constant expression and its value shall be greater than zero.So why does my code work with an explicit
unsigned
size type, with an inferredsigned
size type but not with an inferredunsigned
size type?EDIT Serge wants to know where I'd need the first version. First, this code example is obviously simplified. My real code is a bit more elaborate. The array is actually an array of indices/offsets in another array.
So, logically, the type of the array should be the same as its size type for maximum correctness.Otherwise, I might get a type mismatch (e.g. betweenunsigned int
andstd::size_t
). Admittedly, this shouldn't be a problem in practice since the compiler implicitly converts to the larger of the two types.EDIT 2 I stand corrected (thanks, litb): size and offset are of course logically different types, and offsets into C arrays in particular are of type
std::ptrdiff_t
.解决方案Hmm, the Standard says in
14.8.2.4 / 15
:If, in the declaration of a function template with a non-type template-parameter, the non-type template-parameter is used in an expression in the function parameter-list and, if the corresponding template-argument is deduced, the template-argument type shall match the type of the template-parameter exactly, except that a template-argument deduced from an array bound may be of any integral type.
Providing this example:
template<int i> class A { /* ... */ }; template<short s> void f(A<s>); void k1() { A<1> a; f(a); // error: deduction fails for conversion from int to short f<1>(a); // OK }
That suggests that the compilers that fail to compile your code (apparently GCC and Digital Mars) do it wrong. I tested the code with Comeau, and it compiles your code fine. I don't think there is a different to whether the type of the non-type template parameter depends on the type of the type-parameter or not.
14.8.2.4/2
says the template arguments should be deduced independent from each other, and then combined into the type of the function-parameter. Combined with /15, which allows the type of the dimension to be of different integral type, i think your code is all fine. As always, i take the c++-is-complicated-so-i-may-be-wrong card :)Update: I've looked into the passage in GCC where it spits out that error message:
... type = TREE_TYPE (size); /* The array bound must be an integer type. */ if (!dependent_type_p (type) && !INTEGRAL_TYPE_P (type)) { if (name) error ("size of array %qD has non-integral type %qT", name, type); else error ("size of array has non-integral type %qT", type); size = integer_one_node; type = TREE_TYPE (size); } ...
It seems to have missed to mark the type of the size as dependent in an earlier code block. As that type is a template parameter, it is a dependent type (see
14.6.2.1
).Update: GCC developers fixed it: Bug #38950
这篇关于如何将数组的大小通过与模板类型的模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!