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?
根据标准,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)