I can't seem to wrap my head around what is going wrong with the following example
$ cat repro.cpp
#include <iostream>
using namespace std;
template<class T>
struct S1_t
{
template<class U>
struct inner_t_x {};
using inner_t = inner_t_x<T>;
};
struct Bogus{};
template<class T>
struct Functor1
{
void operator()()
{
cout << "Functor1 FAIL: " << __PRETTY_FUNCTION__ << endl;
}
};
template<>
struct Functor1<typename S1_t<Bogus>::template inner_t_x<Bogus>>
{
void operator()()
{
cout << "Functor1 PASS: " << __PRETTY_FUNCTION__ << endl;
}
};
template<class T>
struct Functor2
{
void operator()()
{
cout << "Functor2 FAIL: " << __PRETTY_FUNCTION__ << endl;
}
};
template<class T>
struct Functor2<typename S1_t<T>::template inner_t_x<T>>
{
void operator()()
{
cout << "Functor2 PASS: " << __PRETTY_FUNCTION__ << endl;
}
};
template<class T>
void eval()
{
Functor1<T>{}();
Functor2<T>{}();
}
int main()
{
eval<S1_t<Bogus>::inner_t>();
return 0;
}
$ clang++ repro.cpp -std=c++11 -Wall && ./a.out
Functor1 PASS: void Functor1<S1_t<Bogus>::inner_t_x<Bogus> >::operator()()
Functor2 FAIL: void Functor2<S1_t<Bogus>::inner_t_x<Bogus> >::operator()() [T = S1_t<Bogus>::inner_t_x<Bogus>]
In the Functor1
, I explicitly specialise on the type Bogus
, and indeed that specialisation is being invoked. However, in the Functor2
the type is allowed to be deduced, but partial specialisation fails and generic template is instantiated instead. Yet, __PRETTY_PRINT__
show the same signature for Functor1
& Functort2
when instantiated.
Can anyone able to explain this behaviour, and is there a way to fix Functor2
partial specialisation to fit this scenario? Thanks!
fwiw: Changing Functor2
partial specialisation to
template<class T>
struct Functor2<typename S1_t<Bogus>::template inner_t_x<T>>
{
void operator()()
{
cout << "Functor2 PASS: " << __PRETTY_FUNCTION__ << endl;
}
};
gives correct output
Functor1 PASS: void Functor1<S1_t<Bogus>::inner_t_x<Bogus> >::operator()()
Functor2 PASS: void Functor2<S1_t<Bogus>::inner_t_x<Bogus> >::operator()() [T = S1_t<Bogus>::inner_t_x<Bogus>]
but this is not the option in my use case.
The specialization of Functor2
will never be used. The compiler could issue a warning about that, but it doesn't in your case. The reason for it being not deducible is simple: Imagine you later add something like
struct Hogus;
template<>
struct S1_t<Hogus>
{
template <typename U>
using inner_t_x = S1_t<Bogus>::inner_t_x<Bogus>;
};
then S1_t<Bogus>::inner_t_x<Bogus>
and S1_t<Hogus>::inner_t_x<Hogus>
would be the same type. Therefore, the template deduction in the partial specialization of Functor2
could yield both T=Bogus
or T=Hogus
. Hence, it cannot be deduced unambiguously under any circumstances.