Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a compiler deduce this class template with forwarding reference?

I am looking into class template deduction available since C++17. Here are the code I would like to ask about:

#include <iostream>
#include <cmath>
using std::endl;
using std::cout;

template<typename T>
struct MyAbs {
     template<typename U>
     MyAbs(U&& u) : t(std::forward<T>(u))
     { cout << "template" << endl;}

#ifdef ON
    MyAbs(const T& t) : t(t) {}
#endif

    T operator()() const
    {
        return std::abs(t);
    }
    T t;
};

/*
  // may need the following
template<typename U>
MyAbs(U&&) -> MyAbs<typename std::remove_reference<U>::type>;
*/

int main()
{
    const double d = 3.14;
    cout << MyAbs(4.7)() << endl;
    cout << MyAbs(d)() << endl;    
    return 0;
}

When MyAbs(const T&) is not conditionally-compiled (i.e. no -DON), both clang++ and g++ fail to deduce the template parameter, T. Given -DON=1, both compilers build the simple example above.

Firstly, I also guessed that the deduction should fail; the compiler could deduce U but not T. The compile errors I got were what I expected. Please, let me know if I am mistaken.

If I was correct on it, then, I cannot understand why the deduction with U&& succeeds when MyAbs(const T&) is added. What I expected was deducing with U&& fails, and SFINAE allows me to invoke MyAbs(const T&) instead for both cases: 4.7 and d. However, what happened is different. This program seems to invoke the template version for 4.7 and non-template version for d.

$ g++ -Wall -std=c++17 ~/a.cc -DON=1
$ ./a.out 
template
4.7
3.14

It seems that the template version has suddenly become viable. Is this expected? If so, what's the reason?

like image 291
Stephen Avatar asked Apr 03 '18 16:04

Stephen


People also ask

What is template argument deduction?

Template argument deduction is used when selecting user-defined conversion function template arguments. A is the type that is required as the result of the conversion. P is the return type of the conversion function template.

What is C++ type deduction?

Type inference or deduction refers to the automatic detection of the data type of an expression in a programming language. It is a feature present in some strongly statically typed languages. In C++, the auto keyword(added in C++ 11) is used for automatic type deduction.

What is Typename C++?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.


1 Answers

Class template argument deduction happens in two stages.

  1. Deduce the class template arguments.
  2. Then, do the actual construction with the concrete class type.

Step 1 only helps you figure out the class template arguments. It does not do anything with regards to the actual constructor (or class template specialization) that may be used in step 2.

The existence of the constructors might drive the deduction, but if a given constructor is used to deduce that says nothing about whether or not it's used to construct.


So, when you just have:

template<typename T>
struct MyAbs {
     template<typename U>
     MyAbs(U&& u);
};

Class template argument deduction fails - you have no deduction guide in your constructor, T is a non-deduced context. The compiler just can't figure out what T you want in MyAbs(4.7) or MyAbs(d).

When you added this one:

template<typename T>
struct MyAbs {
     template<typename U>
     MyAbs(U&& u);

     MyAbs(T const&);
};

Now it can! In both cases, it deduces T as double. And once it does that, then we go ahead and perform overload resolution as if we had typed MyAbs<double> to begin with.

And here, MyAbs<double>(4.7) happens to prefer the forwarding reference constructor (less cv-qualified reference) while MyAbs<double>(d) happens to prefer the other one (non-template preferred to template). And that's okay and expected, just because we used one constructor for deduction doesn't mean we have to use specifically that constructor for construction.

like image 135
Barry Avatar answered Oct 23 '22 15:10

Barry