After a while I discovered again a power of template template-parameters. See e.g. the following snippet:
template <template <class> class TT, class T>
void foo(TT<T>) {
}
template <class T>
using typer = T;
int main() {
foo<typer>(int{});
}
The alias template is passed to the template as a template template-parameter and is used further to detect the other parameter of the template as it is deduced context. Beauty!
However just when the alias template itself need to be deduced it looks like the compilers get crazy:
template <template <class> class>
struct tag{};
template <template <class> class TT, class T>
void foo(tag<TT>, TT<T>) {
}
template <class T>
using typer = T;
int main() {
foo(tag<typer>{}, int{});
}
Compilers of course are right as TT
can be deduced from both tag<TT>
as well as TT<T>
parameters of foo
, and the int{}
doesn't match the template template with type parameter pattern. Is there any way to preserve the deduction context for T
but make TT
non-deduced context in TT<T>
?
P.S. My intentions are pure and this is just a theoretical question with no Y problem behind it.
I think it would be easier/clearer to write something like:
template <template <class> class TT, class T>
void foo(tag<TT>, T, std::enable_if_t< std::is_same<T,TT<T>>::value >* = 0 )
or the less constrained
template <template <class> class TT, class T>
void foo_impl( tag<TT>, TT<T> ){}
template <template <class> class TT, class T>
void foo( tag<TT> a, T b ){ foo_impl<TT>( a, b ); }
as a side note, this shows that the (non normative) note in the standard claiming that An alias template name is never deduced is somewhat inaccurate ...