C++构造函数模板专业化

Fel*_*bek 5 c++ templates constructor template-specialization

我正在尝试为std::string参数创建一个专门的构造函数,但是当我用字符串参数调用它时,总是使用另一个.

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

template <>
Literal::Literal(std::string const& val)
{
    value = val.c_str();
}
Run Code Online (Sandbox Code Playgroud)

如果两者都在类中定义,无论是在类外部还是在发布的示例中都没有关系,那么只在类外部定义特化:当调用时std::string,赋值value = val会产生编译器错误.

如何正确地专门化此构造函数模板std::string

Bat*_*eba 6

你没有.

你应该重载构造函数:Literal(const std::string&),你可以在struct声明中做.

编译器总是尝试在模板之前匹配非模板重载.


kfs*_*one 6

根据标准,14.8.2.1从函数调用推导模板参数 [temp.deduct.call] 其中P是模板参数,A是该位置的函数调用参数:

2 如果 P 不是引用类型:

如果A是数组类型,则使用数组到指针=标准转换([conv.array])产生的指针类型代替A进行类型推导;否则,

如果A是函数类型,则使用函数到指针标准转换([conv.func])产生的指针类型代替A进行类型推导;否则,

如果 A 是 cv 限定类型,则类型推导将忽略 A 类型的顶级 cv 限定符。

如果 P 是 cv 限定类型,则类型推导时将忽略 P 类型的顶级 cv 限定符。如果 P 是引用类型,则使用 P 引用的类型进行类型推导。[...]

所以给出

std::string s{"hello"};
const std::string& sr{s};
Literal l(sr);
Run Code Online (Sandbox Code Playgroud)

A(sr) 是const std::string&,但没有考虑常量性,因此编译器考虑了std::string。这符合你的

template <typename V>
Literal(V val)
{
    value = val;
}
Run Code Online (Sandbox Code Playgroud)

所以它使用了这个专业化。如果你有专门的

template<>
Literal(std::string val)
Run Code Online (Sandbox Code Playgroud)

编译器会找到这种专门化,这可能就是您必须做的并使用移动语义。

#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);
}
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/eJJ5Ch