Consider the following code:
#include <utility>
template<typename T>
struct wrapper {
T value;
};
struct foo {
operator wrapper<int>() {
return{10};
}
};
int main() {
foo f;
wrapper w = f; // error
std::pair p = std::make_pair(1, 0); // ok
}
gcc 7.1.1 fails to compile at the marked line above:
main.cpp: In function 'int main()': main.cpp:17:17: error: class template argument deduction failed: wrapper w = f; // error ^ main.cpp:17:17: error: no matching function for call to 'wrapper(foo&)' main.cpp:4:8: note: candidate: template<class T> wrapper(wrapper<T>)-> wrapper<T> struct wrapper { ^~~~~~~ main.cpp:4:8: note: template argument deduction/substitution failed: main.cpp:17:17: note: 'foo' is not derived from 'wrapper<T>' wrapper w = f; // error ^
f
is convertible to wrapper<int>
, so I expect that to happen. From there the compiler should be able to deduce that T
is int
. But it can't.
The compiler can deduce std::pair
's template parameter correctly, so I'm wondering why this isn't the case with the wrapper
.
Any ideas?
Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones.
Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.
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.
Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.
For class template argument deduction, the "overload set" is composed as described in [over.match.class.deduct/1]. Those are the following:
A set of functions and function templates is formed comprising:
(1.1) - For each constructor of the primary class template designated by the template-name, if the template is defined, a function template with the following properties:
(1.1.1) - The template parameters are the template parameters of the class template followed by the template parameters (including default template arguments) of the constructor, if any.
(1.1.2) - The types of the function parameters are those of the constructor.
(1.1.3) - The return type is the class template specialization designated by the template-name and template arguments corresponding to the template parameters obtained from the class template.(1.2) - If the primary class template C is not defined or does not declare any constructors, an additional function template derived as above from a hypothetical constructor C().
(1.3) - An additional function template derived as above from a hypothetical constructor C(C), called the copy deduction candidate.
(1.4) - For each deduction-guide, a function or function template with the following properties:
(1.4.1) - The template parameters, if any, and function parameters are those of the deduction-guide.
(1.4.2) - The return type is the simple-template-id of the deduction-guide.
As you can see, the matching "function" in 1.1 only attempts to match the argument types to the template parameter types exactly. It doesn't take conversion into account (much like most other template deduction related behavior).
The reason it works for std::pair
is due to item 1.3, and the "copy deduction candidate" it defines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With