C++ 有人可以解释这个给我数组大小的模板代码吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/437150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:20:34  来源:igfitidea点击:

Can someone explain this template code that gives me the size of an array?

c++arraystemplatessize

提问by marsol0x

template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
    return n;
}

The part that I don't get is the parameters for this template function. What happens with the array when I pass it through there that gives nas the number of elements in the array?

我没有得到的部分是这个模板函数的参数。当我将数组传递给n数组中的元素数量时,它会发生什么?

回答by Johannes Schaub - litb

Well, first you have to understand that trying to get a value out of an array can give you a pointer to its first element:

好吧,首先你必须明白试图从数组中获取一个值可以给你一个指向它的第一个元素的指针:

int a[] = {1, 2, 3};
int *ap = a; // a pointer, size is lost
int (&ar)[3] = a; // a reference to the array, size is not lost

References refer to objects using their exact type or their base-class type. The key is that the template takes arrays by reference. Arrays (not references to them) as parameters do not exist in C++. If you give a parameter an array type, it will be a pointer instead. So using a reference is necessary when we want to know the size of the passed array. The size and the element type are automatically deduced, as is generally the case for function templates. The following template

引用引用使用其确切类型或基类类型的对象。关键是模板通过引用获取数组。数组(不是对它们的引用)作为参数在 C++ 中不存在。如果你给一个参数一个数组类型,它将是一个指针。所以当我们想知道传递的数组的大小时,使用引用是必要的。大小和元素类型是自动推导出来的,就像函数模板的情况一样。以下模板

template<typename T, size_t n>
size_t array_size(const T (&)[n]) {
    return n;
}

Called with our previously defined array awill implicitly instantiate the following function:

使用我们之前定义的数组调用a将隐式实例化以下函数:

size_t array_size(const int (&)[3]) {
    return 3;
}

Which can be used like this:

可以这样使用:

size_t size_of_a = array_size(a);


There's a variation I made up some time ago [Edit: turns out someone already had that same idea here]which can determine a value at compile time. Instead of returning the value directly, it gives the template a return type depending on n:

前段时间我做了一个变体[编辑:原来有人在这里已经有了同样的想法]它可以在编译时确定一个值。它不是直接返回值,而是根据以下条件为模板提供返回类型n

template<typename T, size_t n>
char (& array_size(const T (&)[n]) )[n];

You say if the array has nelements, the return type is a reference to an array having size nand element type char. Now, you can get a compile-time determined size of the passed array:

您说如果数组有n元素,则返回类型是对具有 sizen和 element type的数组的引用char。现在,您可以获得传递数组的编译时确定的大小:

size_t size_of_a = sizeof(array_size(a));

Because an array of charhaving nelements has sizeof n, that will give you the number of elements in the given array too. At compile time, so you can do

因为char具有n元素的数组具有sizeof n,所以它也会为您提供给定数组中的元素数。在编译时,你可以这样做

int havingSameSize[sizeof(array_size(a))];

Because the function never is actually called, it doesn't need to be defined, so it doesn't have a body. Hope I could clear the matter up a little bit.

因为函数从不实际调用,它不需要定义,所以它没有主体。希望我能把事情弄清楚一点。

回答by Eclipse

Think of it this way, suppose you had a bunch of functions:

这样想,假设你有一堆函数:

// Note that you don't need to name the array, since you don't
// actually reference the parameter at all.
size_t array_size(const int (&)[1])
{
    return 1;
}

size_t array_size(const int (&)[2])
{
    return 2;
}

size_t array_size(const int (&)[3])
{
    return 3;
}
// etc...

Now when you call this, which function gets called?

现在当你调用这个时,哪个函数被调用?

int a[2];
array_size(a);  

Now if you templatize the arraysize, you get:

现在,如果您对数组大小进行模板化,则会得到:

template <int n>
size_t array_size(const int (&)[n])
{
    return n;
}

The compiler will attempt to instantiate a version of array_size that matches whatever parameter you call it with. So if you call it with an array of 10 ints, it will instantiate array_size with n=10.

编译器将尝试实例化与您调用它的任何参数相匹配的 array_size 版本。所以如果你用一个 10 个整数的数组调用它,它会用 n=10 实例化 array_size。

Next, just templatize the type, so you can call it with more than just int arrays:

接下来,只需对类型进行模板化,这样您就可以使用更多的 int 数组来调用它:

template <typename T, int n>
size_t array_size(const T (&)[n])
{
    return n;
}

And you're done.

你已经完成了。

Edit: A note about the (&)

编辑:关于(&)

The parentheses are needed around the &to differentiate between array of int references (illegal) and reference to array of ints (what you want). Since the precedence of []is higher than &, if you have the declaration:

周围需要括号&来区分 int 引用数组(非法)和对 int 数组的引用(您想要的)。由于 的优先级[]高于&,如果您有声明:

const int &a[1];

because of operator precedence, you end up with a one-element array of const references to int. If you want the &applied first, you need to force that with parentheses:

由于运算符的优先级,您最终会得到一个对 int 的 const 引用的单元素数组。如果你想&先应用,你需要用括号强制它:

const int (&a)[1];  

Now the you have a const reference to a one element array of ints. In the function parameter list, you don't need to specify the name of a parameter if you don't use it, so you can drop the name, but keep the parentheses:

现在您有一个对整数的单元素数组的 const 引用。在函数参数列表中,如果不使用参数名称,则不需要指定参数名称,因此可以去掉名称,但保留括号:

size_t array_size(const int (&)[1])

回答by MSN

Nothing happens to the array. It's an unused parameter that is used to resolve the signature of the template function.

数组没有任何反应。这是一个未使用的参数,用于解析模板函数的签名。

It also cannot be used as a template argument, but that's a separate nit.

它也不能用作模板参数,但这是一个单独的 nit。

回答by TechPriest

A little weird way to get the result as compile-time const for those of us who don't have "constexpr":

对于我们这些没有“constexpr”的人来说,将结果作为编译时常量的一种有点奇怪的方法:

#include <iostream>

namespace
{

    template <size_t V>
    struct helper
    {
        enum
        {
            value = V
        };
    };


    template<typename T, size_t Size>
    auto get_size(T(&)[Size]) -> helper < Size >
    {
        return helper < Size >() ;
    }

    template<typename T>
    struct get_value
    {
        enum
        {
            value = T::value
        };
    };

}

int main()
{
    std::cout << get_value<decltype(get_size("Foo bar baz"))>::value;
}