Gabriel
Gabriel

Reputation: 3077

How to make the compiler use the right template specialization?

Consider the following simplified version of my code. I have a template class A, a template function Fill, and a specialization of the function to work with basic types like int or char, and another specialization to work with A:

#include <sstream>
#include <string>
#include <iostream>

template<size_t C>
class A
{
public:
    A & operator=(std::string v) { 
        data[0] ='a';
        return *this; 
    }
    char data[C];
};

template<typename T> T Fill(std::string value, T default_value);

// Specialization for A<C>
template<size_t C>
A<C> Fill(std::string value, A<C> default_value) 
{
    if (value.empty())
        return default_value;
    A<C> result;
    result = value;
    return result;
}

// Specialization for int, double, char, etc
template<typename T>
T Fill(std::string value, T default_value)
{   
    if (value.empty())
        return default_value;

    T result;
    std::istringstream(value) >> result;
    return result;
}

void main()
{
    int abc = Fill(/*Get a string somehow*/"123", 0); // OK

    A<10> def;
    def = std::string("111");
    A<10> a;
    a = Fill(/*Get a string somehow*/"abc", def);     // OK
}

That works fine although I'm amazed that the compiler manages to match the parameter to the right template specialization.

The problem comes with some typedefs that ease the use of A<x>. Here is a simplified version:

typedef A<12> A12;
...
A<12> def12;
def12 = std::string("12");

A12 a12;
a12 = Fill(/*Get a string somehow*/"xyz", def12);       // Not OK !

The compiler does not detect that the type A12 is actually A<12> and uses the wrong specialization of the function, which does not compile because istringstream cannot parse with operator>> into an A.

How can I make it use the right template specialization ?

Upvotes: 2

Views: 164

Answers (3)

Luc Danton
Luc Danton

Reputation: 35449

The compiler does not detect that the type A12 is actually A<12> and uses the wrong specialization of the function

Actually since you're passing A<12> def; in your example (mistake?), the correct overload (see my comment on the question) should be picked. The fact that you're assigning the result to A12 a; shouldn't affect overload resolution.

If you meant the opposite (passing A12 and assigning to whatever) then this could be a compiler deficiency. This works correctly here.

Upvotes: 0

Robᵩ
Robᵩ

Reputation: 168596

typedef A<12> A12;
...
A12 a12;
a12 = Fill(/*Get a string somehow*/"xyz", def);       // Not OK !

In this example, you have not shown us the type of def. Assuming that it is the same as the previous example, namely A<10>, this will certainly fail.

In your template, the type of the second parameter must match the return type. Try this:

typedef A<12> A12;
...
A12 a12;
A12 def12;
a12 = Fill(/*Get a string somehow*/"xyz", def12);       // OK !

Upvotes: 1

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272467

Template specializations are not inferred via where you're assigning the return value to. You'll have to explicitly instantiate the correct version:

a12 = Fill<A<12> >("xyz", def);

(or whatever it is that you need...)

Upvotes: 4

Related Questions