Reputation: 58
In the next code, the template argument deduction fails when I try to pass a std::tuple
of reference derived classes as argument to the function that receive a std::tuple
of reference base classes. Why the compiler can not be deduced the template arguments T1
and T2
? and How can I fix it?
// Example program
#include <iostream>
#include <tuple>
template<typename T>
struct Base {};
template<typename T>
struct Derived1 : Base<T> {};
template<typename T>
struct Derived2 : Base<T> {};
template<typename T1, typename T2>
void function(std::tuple<Base<T1>&,Base<T2>&> arg)
{
std::cout << "Hello\n";
}
int main()
{
Derived1<int> d1;
Derived2<double> d2;
//function(std::tie(d1, d2)); /* In this case the template argument deduction/substitution failed */
function<int,double>(std::tie(d1, d2)); /* here works */
Base<int>& b1 = d1;
Base<double>& b2 = d2;
function(std::tie(b1, b2)); /* but, in this case also works */
}
This is the compile error for the line code function(std::tie(d1, d2));
:
In function 'int main()':
25:30: error: no matching function for call to 'function(std::tuple<Derived1<int>&, Derived2<double>&>)'
25:30: note: candidate is:
15:6: note: template<class T1, class T2> void function(std::tuple<Base<T>&, Base<T2>&>)
15:6: note: template argument deduction/substitution failed:
25:30: note: mismatched types 'Base<T>' and 'Derived1<int>'
25:30: note: 'std::tuple<Derived1<int>&, Derived2<double>&>' is not derived from 'std::tuple<Base<T>&, Base<T2>&>'
Upvotes: 3
Views: 1563
Reputation: 50550
Deduction doesn't work this way. It pulls in before any conversion or whatever. Here the compiler expects a Base<T>
from which to deduce T
and you are trying to pass a DerivedN<T>
. They are completely different beasts from the point of view of the type system and the function is discarded when trying to find a good match for the call.
Look at the error, it's quite clear.
How can I fix it?
You can use something like this to have them accepted and still force the fact that they derive from Base
:
#include<type_traits>
// ...
template<template<typename> class C1, template<typename> class C2, typename T1, typename T2>
std::enable_if_t<(std::is_base_of<Base<T1>, C1<T1>>::value and std::is_base_of<Base<T2>, C2<T2>>::value)>
function(std::tuple<C1<T1>&, C2<T2>&> arg)
{
std::cout << "Hello\n";
}
// ...
See it up and running on wandbox.
Upvotes: 1