Unfortunately not this way...
- I want, in no point, try to get into the "Whys" the standard decided not to allow a partial specialization expressed this way – (or if specific wordings on it has been forgotten).
- There are people here who are undoubtedly way more skilled than me at deciphering the convoluted subtleties of the wordings of the standard... ;)
That said, ...
- If someone is looking for ways to implement a solution to this problem – (perfectly standard ways) – here are information and examples that will most likely help in solving your issue...
° Number of template parameters.
- Before showing a means with which a specialization based on the number of parameters of a template template parameter can be achieve, I'm going to briefly talk about the template parameters in themselves.
(I might need to be corrected on the wordings, but the point should be clear enough)
The whole point with templates, when it comes to use them:
- In using aliases.
- With or without arguments.
- Within dispatching traits.
- Within detection traits.
- Within specializations.
is about having the best possible understanding of when the types it receives have to be called parameters, and when to called them arguments...
It might seem obvious to you at first, but you might also be surprised to read that I have posted a very detailed solution, answering another question, to detect the number of parameters declared by a template.
The solution describes the searching process by first trying to 'count' the arguments passed to a template. In the end, because everything in the solution has been done only on forward declarations of templates which are never fully defined, I realized that it was a detection algorithm, because the results are obtained while none of the Victim
templates gets ever instantiated...
- Fully detailed explanations and implementation: here
° Template template parameter specialization.
(Back to the initial wondering)
I was trying to do the exact same type of specialization, shown in the very first code example of the question, to create some king of an implementation selector when I found this question...
I said to my self: "Ok, it seems that one cannot do it like that..."
Because of what I already did for the detection of the number of parameters declared by a template (referenced by the link above), I quickly found a means to produce the desired effect. I thought it would certainly be of use for others, and I've decided to post it here...
I think that the code is rather self-explanatory, so it shouldn't need more explanations.
// Helper to make the static_assert 'name-dependent'.
template<typename...> using AlwaysFalse = std::false_type;
// Primary template should only signal the error...
template<typename Trait>
struct ImplSelect {
static_assert(
AlwaysFalse<Trait>::value,
"Missing specialization..."
);
};
// Specialization for a template with one type parameter.
template<template <typename> class Trait, typename T>
struct ImplSelect<Trait<T>> { using Type = Trait<int>; };
// Specialization for a template with two type parameters.
template<template <typename, typename> class Trait, typename T, typename U>
struct ImplSelect<Trait<T, U>> { using Type = Trait<int, int>; };
/* [ Note ] These are ONLY forward declarations.
* They aren't instatiated within this code.
*/
template<typename T> struct Victim1;
template<typename T, typename U> struct Victim2;
/* [ Note ] Opaque type tags (forward declarations).
* Allows for further tag dispatching if desired.
*/
struct Tag1; struct Tag2;
/* Selection of Victim1<int> and Victim2<int, int>.
* Not instantiated yet...
*/
using Impl1 = typename ImplSelect<Victim1<Tag1>>::Type;
using Impl2 = typename ImplSelect<Victim2<Tag1, Tag2>>::Type;
Enjoy !
foo<bar>
withtemplate<typename...> struct bar {};
is ambiguous, isn't it? – Nikita Kniazevfoo
being used. But it seems even more complicated, see the strange behavior of gcc here. It unconditionally uses the specialized version... – llllllllllfoo<bar> f; f.show()
... observe that print "specialized" if you compile C++17, "primary" if you compile C++14; something is changed in C++17 about template-template matching (but I'm not saying g++ is right... I'm really, really confused). – max66