Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Help with a template specialization

Tags:

c++

templates

I'm working with/learning template function specialization rules. I start with this function

template<typename T>
std::string toString(const T& t)
{
    ostringstream out;
    out << t;
    return out.str();
}

Now I'd like to specialize it for const char*

typedef const char* ccharPtr;

template<>
std::string toString(const ccharPtr& s)
{
    cout << "in specialization" << endl; // just to let me know
    return std::string(s);
}

I'd like to do that without a typedef, but so far I can't figure it out.

That specialization works for a const char*, but not for a char*.

const char* s1 = "Hi"
cout << toString(s1); // works
char s2[] = "There";
cout << toString(s2); // doesn't work, since s2 isn't const char*
cout << toString(", Bob"); // doesn't work. Why not?

I'd like a single specialization to work for each case, but having trouble figuring it out.

like image 521
John Avatar asked Dec 06 '22 20:12

John


1 Answers

Why specialise? Just overload the function. Fully specialising function templates is usually not required.

template <typename T>
std::string toString(const T& in)
{
    ostringstream out;
    out << in;
    return out.str();
}

std::string toString(char const* in)
{
    return in;
}

OK, if you really want to do this, then you have to consider that the type of string literals — although they implicitly convert to char const* — is char const[N].

template <typename T>
std::string toString(T const & t) {
    ostringstream out;
    out << t;
    return out.str();
}

template <>
std::string toString(char const* const & s) {
    cout << "(S1)";
    return std::string(s);
}

template <size_t N>
std::string toString(char (&s)[N]) {
    cout << "(S2)";
    return std::string(s);
}

template <size_t N>
std::string toString(char const (&s)[N]) {
    cout << "(S3)";
    return std::string(s);
}

int main() {
    const char* s1 = "Hi";
    cout << toString(s1) << endl;
    char s2[] = "There";
    cout << toString(s2) << endl;
    cout << toString(", Bob") << endl;
}

// Output:
// (S1)Hi
// (S2)There
// (S3), Bob

Live demo.

You can omit specialisation S2, and then both "There" and ", Bob" will use S3.

Be warned that, actually, this isn't specialisation at all. I've rather cheated by creating new function templates. But I had to to get the size_t parameter in; you could only do real specialisation here if you picked one value for N and wrote it into the function signature as part of a concrete type, or if you could partially specialise function templates.

like image 199
Lightness Races in Orbit Avatar answered Dec 22 '22 15:12

Lightness Races in Orbit