Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template argument deduction failure while passing address of const type

template <typename T>
T go(T a, T *b){ T *t; return *t;}

int main() {
    const int x = 10;
    go(x, &x);
    return 0;
}

Gives compiler error:

error: no matching function for call to ‘go(const int&, const int*)’

Why is the first argument a reference type const int& instead of just const int?

To fix this compilation error, I overrode the compiler deduction process by specifying the type of arguments go<const int>(x, &x);, but again why do I need to do that?

like image 200
Saurav Sahu Avatar asked Sep 19 '17 12:09

Saurav Sahu


People also ask

What is template argument deduction in C++?

Class Template Argument Deduction (CTAD) is a C++17 Core Language feature that reduces code verbosity. C++17's Standard Library also supports CTAD, so after upgrading your toolset, you can take advantage of this new feature when using STL types like std::pair and std::vector.

What is a non type template parameter?

A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument. A non-type parameter can be any of the following types: An integral type. An enumeration type. A pointer or reference to a class object.

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.


2 Answers

It's a conflict of type deduction. T is deduced as int from the first argument, and as const int from the second argument. Hence type deduction fails (and the compiler presents a message which may or may not make the underlying cause clear).

If you want to make this function work without having to specify the template argument explicitly, you could make it so that only the second function argument drives the deduction:

template <class T>
struct NonDeduced { using type = T; }

template <class T>
T go(typename NonDeduced<T>::type a, T *b) { T *t; return *t; }

That way, T will only be deducible from the second argument, and the first parameter will use the deduced T without modification.

like image 143
Angew is no longer proud of SO Avatar answered Sep 28 '22 12:09

Angew is no longer proud of SO


Because a is declared to be passed by value, then in template argument deduction:

c) otherwise, if A is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction:

That means, for go(x, &x);, for the 1st argument x, the template parameter T will be deduced as int, not const int. For the 2nd argument T will be deduced as const int, because b is declared to be passed by pointer (and the cv-qualifiers on the object being pointed are reserved; the same thing happens for pass-by-reference). Then deduction fails.


BTW: clang gives quite clear message for it:

prog.cc:4:3: note: candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'const int')

like image 30
songyuanyao Avatar answered Sep 28 '22 11:09

songyuanyao