Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are qualifiers of template arguments stripped when deducing the type?

While building a little sample program with Microsoft VisualStudio 2008 I noticed an odd thing about the deduction of types passed to templates. Consider this example:

template<class T>
void f( T v ) {
    x; // trigger a compile error
    (void)v;
}

template<class T>
void g( T v ) {
    f( v );
}

void h() {
  int i;
  g<const int &>( i );
}

Compiling this example using cl /c foo.cpp yields a compile error (as intended). What's interesting is the value of the 'T' template parameter. Here's what VisualStudio 2008 prints:

mini.cpp(3) : error C2065: 'x' : undeclared identifier
        mini.cpp(9) : see reference to function template instantiation 'void f<int>(T)' being compiled
        with
        [
            T=int
        ]
        mini.cpp(14) : see reference to function template instantiation 'void g<const int&>(T)' being compiled
        with
        [
            T=const int &
        ]

Note how in g, the type of the argument is const int & but in f it's just int. Apparently the reference-to-const part was stripped while deducing the type to use when instantiating the f template. When adjusting the example so that f is invoked like

f<T>( v );

the type is const int & in both f and g. Why is that? Is this specified behaviour? I secretly relied on the type of the v function argument to be passed to f but apparently it's not.

like image 832
Frerich Raabe Avatar asked Nov 12 '10 12:11

Frerich Raabe


People also ask

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.

Why do we use template template parameter?

8. Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.

What is template argument deduction?

Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.

What is a template argument?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


2 Answers

The answer is that although the variable v has type const int &, the expression v is an lvalue expression with type const int.

litb provides the text (5/6): "If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to “T” prior to any further analysis, the expression designates the object or function denoted by the reference, and the expression is an lvalue."

An "argument" is "an expression in the comma-separated list bounded by the parentheses in a function call expression" (1.3.1). So in 14.8.2.1:

  • "the corresponding argument type of the call (call it A)" is const int.
  • "If A is a cv-qualified type, the top-level cv-qualifiers of A's type are ignored for type deduction" (hence, int).
  • "the deduction process attempts to find template argument values that will make the deduced A identical to A" (so T is int)
like image 116
Steve Jessop Avatar answered Oct 14 '22 23:10

Steve Jessop


http://accu.org/index.php/journals/409 is a rather extensive article, but it explains the process. From the template parameters, a parameter type P is derived, and this is matched to an argument type A. The relevant part is where it describes how a target type A is derived from the function argument: for non-array types, references are simply stripped. Hence, if the type of the argument is int&, then the target type A is simply int.

This is the simple reason: because the standard tells us so. What is the rationale? As it happens, the article has a footnote pointing that out too. In your example, typeid(v)==typeid(const int). When used in non-lvalue contexts, reference types behave like non-reference types.

like image 35
MSalters Avatar answered Oct 15 '22 00:10

MSalters