如何将数组的大小通过与模板类型的模板? [英] How to pass an array size as a template with template type?

查看:271
本文介绍了如何将数组的大小通过与模板类型的模板?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的编译器的行为很奇怪,当我尝试到一个固定大小的数组传递给一个模板函数。在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 to unsigned 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 forces char 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 inferred signed size type but not with an inferred unsigned 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. between unsigned int and std::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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆