MTMD
MTMD

Reputation: 1232

Why non deductible template parameters is problematic?

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

Answers (2)

einpoklum
einpoklum

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

bolov
bolov

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

Related Questions