Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto detection of template parameters without arguments

Tags:

c++

c++11

This is an offshoot of an answer to another SO post.

I have the following working code, with the expected output.

#include <iostream>

template <typename T>
T twice(T in)
{
   return 2*in;
}

struct Foo
{
   Foo operator+(int (*func)(int in)) const
   {
      Foo ret{data};
      ret.data += func(ret.data);
      return ret;
   }
   int data;
};

int main()
{
   Foo f1{20};
   Foo f2 = f1 + twice;
   Foo f3 = f1 + twice<int>;
   std::cout << f2.data << std::endl;
   std::cout << f3.data << std::endl;
}

I did not know until yesterday that the compiler can deduce the type parameters of a function template even without an argument. In the code above, the expressions

f1 + twice

and

f1 + twice<int>

result in identical values.

My question is: Where in the C++03/C++11 standard can we find the necessary supporting documentation for the compiler's auto type detection logic?

like image 434
R Sahu Avatar asked Mar 20 '23 05:03

R Sahu


2 Answers

C++11 14.8.2.2 Template arguments can be deduced from the type specified when taking the address of an overloaded function.

Here, the type specified by the parameter type of operator+ is int (*)(int), the overloaded function is twice, so int is deduced as the template argument to give a matching function type. See 14.8.2.5 if you need the gory details of that deduction.

like image 59
Mike Seymour Avatar answered Apr 02 '23 03:04

Mike Seymour


This is closest to the actual c++11 standard but still openly available version of draft I've found: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf.

I believe the template parameter deduction is done when you write Foo f2 = f1 + twice; and pass twice as a function address. twice gets passed as an address of a function to the operator+. I believe the following mechanism kicks in:

14.8.2.2 Deducing template arguments taking the address of a function template [temp.deduct.funcaddr]:

Template arguments can be deduced from the type specified when taking the address of an overloaded function (13.4). The function template’s function type and the specified type are used as the types of P and A, and the deduction is done as described in 14.8.2.5.

So the actual template deduction will be done basing on the type of the funct. I believe the relevant paragraphs from 14.8.2.5 are 1 and 2.

14.8.2.5 Deducing template arguments from a type [temp.deduct.type]`:

1 Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.

2 In some cases, the deduction is done using a single set of types P and A, in other cases, there will be a set of corresponding types P and A. Type deduction is done independently for each P/A pair, and the deduced template argument values are then combined. If type deduction cannot be done for any P/A pair, or if for any pair the deduction leads to more than one possible set of deduced values, or if different pairs yield different deduced values, or if any template argument remains neither deduced nor explicitly specified, template argument deduction fails.

Basically you pass twice as a pointer to the operator+, and then template arguments get deduced via type of the function as defined in operator+. So you have an actual type A that is int (*)(int in) and template types P of twice that gets matched against A and only int twice(int) fits.

I hope I got everything right.

like image 33
luk32 Avatar answered Apr 02 '23 01:04

luk32