代码之家  ›  专栏  ›  技术社区  ›  Konrad Rudolph

如何将数组大小作为模板类型传递给模板?

  •  12
  • Konrad Rudolph  · 技术社区  · 17 年前

    当我试图将固定大小的数组传递给模板函数时,我的编译器的行为异常。代码如下所示:

    #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)
    }
    

    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 .

    部分[ dcl.type.simple

    这个 signed 说明符力 char

    dcl.array ]:

    如果 expr.const )如果存在,则应为积分常数表达式,且其值应大于零。

    unsigned 大小类型,带有推断的 签署 大小类型,但不包含推断的 未签名 尺码类型?

    因此,从逻辑上讲,数组的类型应该与其大小类型相同,以获得最大的正确性。 无符号整型 std::size_t

    编辑2 我的观点是正确的(谢谢,litb):大小和偏移量在逻辑上当然是不同的类型,特别是C数组中的偏移量是不同的类型 std::ptrdiff_t .

    1 回复  |  直到 13 年前
        1
  •  16
  •   Johannes Schaub - litb    17 年前

    嗯,标准上说 14.8.2.4 / 15 :

    如果在具有非类型模板参数的函数模板声明中,在函数参数列表中的表达式中使用了非类型模板参数,并且如果推导了相应的模板参数,则模板参数类型应与模板参数的类型完全匹配, 但是,从数组边界推导出的模板参数可以是任何整数类型。

    举个例子:

    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
    }
    

    14.8.2.4/2 表示模板参数应相互独立推导,然后组合到函数参数的类型中。结合/15,它允许维度的类型为不同的整数类型,我认为您的代码都很好。和往常一样,我拿的是一张c++-is-complex-so-i-may-be-error-card:)

    使现代化 当前位置我已经查看了GCC中的一段,其中给出了错误消息:

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

    在前面的代码块中,它似乎没有将大小的类型标记为dependent。由于该类型是模板参数,因此它是从属类型(请参见 14.6.2.1

    更新: GCC开发者修复了它: Bug #38950