1

I'm trying to use template specialization so that I can have specialized behavior for different types. However, I'm unable to get a template specialization for a string literal type (const char[N]) to bind to the specialized template.

I have a simple template select_type<T>, with the following specializations:

template <class T>
struct select_type
{
    static void action()
    {
        cout << "Generic type" << endl;
    }
};

template <>
struct select_type<std::string>
{
    static void action()
    {
        cout << "Specialization for string" << endl;
    }
};

template <std::size_t N>
struct select_type<const char[N]>
{
    static void action()
    {
        cout << "Specialization for const char array" << endl;
    }
};

When I attempt to instantiate each specialization as follows:

select_type<int>::action();
select_type<std::string>::action();
select_type<decltype("abc")>::action();

... I get the following output:

Generic type
Specialization for string
Generic type

Note that the specialization for char arrays is not invoked, even though decltype(abc) should produce the type const char[4].

I thought that perhaps some type of type decay was occurring, so I added in a specialization for const char*, but it still wasn't selected.

So, why does the expression:

select_type<decltype("abc")>::action();

fail to invoke the specialization for const char[N]?

Siler
  • 8,976
  • 11
  • 64
  • 124

1 Answers1

4

You are seeing this behavior because of how decltype deduces the type. String literals are lvalues. From [expr.prim.general]/p1:

A string literal is an lvalue; all other literals are prvalues.

decltype() returns an lvalue-reference type for lvalues. [dcl.type.simple]/p4

For an expression e, the type denoted by decltype(e) is defined as follows:

(4.1) — if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;

(4.2) — otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;

(4.3) — otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

(4.4) — otherwise, decltype(e) is the type of e.

So your specialization needs to be as follows:

template <std::size_t N>
struct select_type<const char (&)[N]>
David G
  • 94,763
  • 41
  • 167
  • 253