Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ constructor template specialization

I'm trying to create a specialized constructor for std::string arguments, but the other one is always used when I call it with a string argument.

struct Literal : Expression
{    
    template <typename V>
    Literal(V val)
    {
        value = val;
    }
};

template <>
Literal::Literal(std::string const& val)
{
    value = val.c_str();
}

It doesn't matter if both are defined inside the class, both outside the class, or like in the posted example only the specialization is defined outside the class: When called with std::string, the assignment value = val gives a compiler error.

How do I correctly specialize this constructor template for std::string?

like image 266
Felix Dombek Avatar asked Jul 29 '16 16:07

Felix Dombek


People also ask

What is meant by template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

Are template specializations inline?

An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.

How do I force a template instantiation?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

What is the difference between Typename and class in template?

There is no semantic difference between class and typename in a template-parameter. typename however is possible in another context when using templates - to hint at the compiler that you are referring to a dependent type. §14.6.


2 Answers

You don't.

You should overload the constructor: Literal(const std::string&), which you can do in the struct declaration.

The compiler always tries to match non-template overloads before template ones.

like image 118
Bathsheba Avatar answered Oct 20 '22 19:10

Bathsheba


According to the standard, 14.8.2.1 Deducing template arguments from a function call [temp.deduct.call] where P is the template parameter and A is the function-call argument in that position:

2 If P is not a reference type:

If A is an array type, the pointer type produced by the array-to-pointer = standard conversion ([conv.array]) is used in place of A for type deduction; otherwise,

If A is a function type, the pointer type produced by the function-to-pointer standard conversion ([conv.func]) is used in place of A for type deduction; otherwise,

If A is a cv-qualified type, the top-level cv-qualifiers of A's type are ignored for type deduction.

If P is a cv-qualified type, the top-level cv-qualifiers of P's type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction. [...]

So given

std::string s{"hello"};
const std::string& sr{s};
Literal l(sr);

A (sr) is const std::string& but the constness is not considered, so the compiler considered std::string. This matches your

template <typename V>
Literal(V val)
{
    value = val;
}

and so it uses this specialization. If you had specialized

template<>
Literal(std::string val)

the compiler would find this specialization, and this is probably what you will have to do and use move semantics.

#include <iostream>
#include <string>

struct S {
    template<typename T>
    S(T t) { std::cout << "T t\n"; }

    std::string value_;
};

template<>
S::S(std::string value) {
    std::cout << "string\n";
    value_ = std::move(value);
}

template<>
S::S(const std::string&) {
    std::cout << "const string&\n";
}

int main() {
    S s1(42);

    std::string foo{"bar"};
    const std::string& foor = foo;
    S s2(foo);
    S s3(foor);
}

http://ideone.com/eJJ5Ch

like image 40
kfsone Avatar answered Oct 20 '22 21:10

kfsone