Reputation: 1232
Trying to compile this piece of code results in an error.
template <typename T>
struct MyClass;
template <typename T, std::size_t sz>
struct MyClass<T> {
static void print() {
std::cout << "Partially specialized" << std::endl;
}
};
error: template parameters not deducible in partial specialization
Trying to make it possible to deduce sz
solves the problem. For example:
template <typename T, std::size_t sz>
struct MyClass<T[sz]> {
static void print() {
std::cout << "Partially specialized" << std::endl;
}
};
My question is, how does the compiler interprets such a program and what's the rational behind not allowing to have the first structure?
Further clarification:
I am thinking that if the inital code was compilable, we could use it in a manner such as: MyClass<int, 4>::print()
.
Upvotes: 0
Views: 479
Reputation: 131970
In C++, after we declare a template, we can specialize it if we like, e.g.:
template <typename T> foo;
template <typename U> foo<U*>;
the compiler will now expect a different definition for pointer types. But - the specialization needs to actually specialize - it can't be as general as the original declaration. In your case, you're adding a template parameter. It's not even about its deduction - it's just not something you can do.
Thus, if you look at the error messages other compiles give you:
(clang:)
<source>:7:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
struct MyClass<T> {
^ ~~~
<source>:6:1: error: too many template parameters in template redeclaration
template <typename T, std::size_t sz>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(MSVC:)
<source>(11): error C2753: 'MyClass<T>': partial specialization cannot match argument list for primary template
<source>(11): error C2764: 'sz': template parameter not used or deducible in partial specialization 'MyClass<T>'
You'll see the different focus in error message rhetoric: You must specialize, and yet you aren't.
On the other hand, in your second code snippet, you are specializing: Now you're not defining MyClass
for all types T
, but only for arrays of a certain number of elements. You should really think about it as:
template <typename U, std::size_t sz>
struct MyClass<U[sz]> {
static void print() {
std::cout << "Partially specialized" << std::endl;
}
};
so the specialization is for when T
is of the form U[sz]
.
Upvotes: 1
Reputation: 75805
I am thinking that if the inital code was compilable, we could use it in a manner such as:
MyClass<int, 4>::print()
.
That's not how template specialization works. If you declare the base template as template <class T> struct MyClass
then MyClass
can only be instantiated with just one template type parameter. It cannot be instantiated as MyClass<int, int>
or MyClass<int, 3>
or MyClass<3>
.
Template specialization can just specialize on the base template parameters.
Going back to your problem. So MyClass
can be instantiated like so: MyClass<int>
, MyClass<float>
, MyClass<SomeClass>
, MyClass<int*>
, MyClass<int[10]>
and so on and so on.
When you write
template <typename T, std::size_t sz>
struct MyClass<T[sz]> {
You specialize the template MyClass<T>
for any T
that is an array or any type of any size. For instance MyClass<int[24]>
will use this specialization.
When you write
template <typename T, std::size_t sz>
struct MyClass<T> {
// ^
// no sz here
That looks like a specialization of MyClass
but it is not, because sz
does not appear in the specialization paramters.
Upvotes: 1