(IMHO) The most common reasons the standard disallows a specific feature are:
- The feature is covered by another mechanism in the language, rendering it superfluous.
- It contradicts existing language logic and implementation, making its implementation potentially code breaking.
- Legacy: the feature was left out in the first place and now we've built a lot without it that it's almost forgotten (see partial function template specialization).
Difficulty of implementation is rarely a factor, though it may take some time for compiler implementations to catch up with evolution on the "hard" stuff.
You could always wrap your non type template parameter in another type:
template < typename T1, typename T2 >
struct Demo {}; // primary template
template < typename T >
struct Demo<T, integral_constant<T, 0>> {}; // specialization
I doubt this hack falls into case 1. Case 3 is always a possibility so lets examine case 2. To do this, we have to know which are the related rules the standard imposes on class templates partial specializations.
14.5.5 Class template partial specializations
A non-type argument is non-specialized if it is the name of a non-type parameter. All other non-type arguments are specialized. (C1)
Within the argument list of a class template partial specialization, the following restrictions apply:
- A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier. (C2)
- The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. (C3)
I marked the first three Clauses I found relevant (the third is the one in question). According to C1 in our case we have a specialized non-type argument so C2 should stand, yet this
template <class T, T t> struct C {};
template <class T> struct C<T, 1>;
is actually
template <class T, T t> struct C {};
template <class T> struct C<T, T(1)>; // notice the value initialization
so the partially specialized non type argument T t
involves the template parameter of the partial specialization class T
in an expression other than an identifier; furthermore such specializations are bound to involve class T
in a value initialization which will always be a violation of the rules. Then C3 comes along and clears that out for us so that we won't have to make that deduction every time.
So far we've established that the rules are in sync with themselves but this does NOT prove case 2 (once we remove the initial limitation every other related limitation falls apart). We'd have to dive into matching class template partial specializations rules; partial ordering is considered out of scope here because if we can produce valid candidates it's up to the programmer to put together a well formed program (i.e. not create ambiguous uses of class templates).
Section
Matching of class template partial specializations [temp.class.spec.match]
describes the (give or take) "pattern matching" process involved in template specialization. Rule 1
is the overall workflow of the procedure and the subsequent rules are those that define correctness
A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list
A non-type template argument can also be deduced from the value of an actual template argument of a non-type parameter of the primary template.
In a type name that refers to a class template specialization, (e.g., A) the argument list shall match the template parameter list of the primary template. The template arguments of a specialization are deduced from the arguments of the primary template.
These rules are not violated by allowing the type of a template parameter corresponding to a specialized non-type argument to be dependent on a parameter of the specialization. So IMHO there is no specific reason why we can't have this feature in future revisions of the language: legacy is to blame. Sadly I didn't manage to find any language proposals with the initiative to introduce this feature.
static const int value = 42;
and some other types that havestatic const char value = 'a'
, then potentially you could partially specialize a template based on<typename T, T::v>
... I can't think of any particular reason for the restriction, I don't think allowing that kind of substitution and pattern matching would be harder than the kind they already do. But maybe I'm missing something. – Iorgosnew
allows for the programmer to specify the memory location if such fine grained use is actually warranted and factory functions can be generated in place of a constructor. – Pinnatemplate <typename CLASS, typename...ARGs> CLASS factory(ARGs&&...args) { return CLASS(std::forward<ARGs...>(args...)); }
your function pointer would beauto pConstrutor = &factory<class_name, arg0_t, ..., argN_t>
, and your call would beclass_name var = pConstructor(arg0, ..., argN)
. And that will be my last post for this OT thread – Pinna