简体   繁体   中英

why type deduction does not work as expected?

I have a small question about type deduction in C++ metaprogramming. There is a certain function do some action.

main.cpp

template<typename T> void foo(T arg) {
    // do some action on argument
    std::cout << typeid(arg).name() << std::endl;
}


int main(int argc, char** argv) {
    int array[100] = {0};
    std::cout << typeid(array).name() << std::endl;
    foo(array);

    return 0;
}

Output:

A100_i
Pi     

Why arg in function foo() have a another data type than array in function main() ?

Actually when you pass an array to a function, it decays to a pointer type. So T is deduced to be int* , instead of int[100] .

If you want to prevent the decay, accept the parameter by reference .:

template<typename T> void foo(T & arg) //Note `&` here!
{
  // do some action on argument
   std::cout << (typeid(arg).name() << std::endl;
}

Now it will print what you expect, ie A100_i . See this online demo .


Question: Why does the array decay to pointer type when we pass by value ?

Answer: Because in C++ arrays (and functions) cannot be passed by value . The language doesn't allow that. Instead the language requires them to decay into pointer type when they are passed as function arguments. To prevent decay, we need to pass them as reference .

Because C style arrays are broken. In particular, you cannot have a function argument with a C style array type; if you write a function (forgetting about templates for the moment):

void foo( int arg[100] );

the language requires the compiler to treat this as:

void foo( int* arg );

(and the 100 is just a comment—it is ignored by the compiler).

In order to support this in the case of templates, if the compiler is trying to match a non-reference template argument, it will convert an array argument to a pointer, and type deduction will result in the pointer type, not the array type.

The result is that you should never write a function (template or otherwise) expecting a C style array (except for the second argument of main , where you don't have a choice).

Since this brokeness is only present for reasons of C compatibility, C++ doesn't follow it when references are involved. So:

template < typename T, size_t N >
void foo( T (&arg)[ N ] );

will work, and should give you the same results in both cases. If you think that your function might be called with both C style arrays and other things (eg std::vector), you can overload it for both. The version above is more specialized, and will be preferred to the more generic version if possible.

A better solution would be to avoid C style arrays entirely, but they are useful for static variables with initialization; it's only with C style arrays that you can get the compiler to count the number of elements, and define the size of the array according to the initializer list. And have static initialization; std::vector will count the initializers at runtime, but used as a static variable, may cause order of initialization problems. C style arrays and

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM