C++构造函数模板特化
C++ 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();
}
无论两者是在 class 内定义,还是在 class 外定义,或者像发布的示例一样,仅在 class 外定义专业化:当用 std::string
调用时,赋值 value = val
给出编译器错误。
如何为 std::string
正确地专门化此构造函数模板?
你不知道。
您应该重载 构造函数 :Literal(const std::string&)
,您可以在 struct
声明中执行此操作。
编译器总是尝试在模板重载之前匹配非模板重载。
很多时候,当重载是一种解决方案时,人们会尝试定义完全专业化。但过载可能是一个更好的解决方案。在您的情况下,我将使用字符串参数创建一个新的构造函数。
请记住,在重载决策中只考虑基本模板。下面这篇文章是理解这个想法的一个很好的参考:
http://www.gotw.ca/publications/mill17.htm
更新:
无论如何,为了改进我的回答,您可以尝试以下基本模板构造函数:
template <typename V>
Literal(V const& val)
{
value = val;
}
根据 standard, 14.8.2.1 从函数调用中推导模板参数 [temp.deduct.call] 其中 P
是模板参数,A
是函数调用参数该职位:
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. [...]
如此给出
std::string s{"hello"};
const std::string& sr{s};
Literal l(sr);
A
(sr) 是const std::string&
但是没有考虑constness,所以编译器考虑了std::string
。这符合您的
template <typename V>
Literal(V val)
{
value = val;
}
所以它使用了这个专业化。如果你有专业
template<>
Literal(std::string val)
编译器会发现这种特化,这可能是您必须做的并使用移动语义。
#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);
}
我正在尝试为 std::string
个参数创建一个专门的构造函数,但是当我用一个字符串参数调用它时总是使用另一个构造函数。
struct Literal : Expression
{
template <typename V>
Literal(V val)
{
value = val;
}
};
template <>
Literal::Literal(std::string const& val)
{
value = val.c_str();
}
无论两者是在 class 内定义,还是在 class 外定义,或者像发布的示例一样,仅在 class 外定义专业化:当用 std::string
调用时,赋值 value = val
给出编译器错误。
如何为 std::string
正确地专门化此构造函数模板?
你不知道。
您应该重载 构造函数 :Literal(const std::string&)
,您可以在 struct
声明中执行此操作。
编译器总是尝试在模板重载之前匹配非模板重载。
很多时候,当重载是一种解决方案时,人们会尝试定义完全专业化。但过载可能是一个更好的解决方案。在您的情况下,我将使用字符串参数创建一个新的构造函数。 请记住,在重载决策中只考虑基本模板。下面这篇文章是理解这个想法的一个很好的参考: http://www.gotw.ca/publications/mill17.htm
更新:
无论如何,为了改进我的回答,您可以尝试以下基本模板构造函数:
template <typename V>
Literal(V const& val)
{
value = val;
}
根据 standard, 14.8.2.1 从函数调用中推导模板参数 [temp.deduct.call] 其中 P
是模板参数,A
是函数调用参数该职位:
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. [...]
如此给出
std::string s{"hello"};
const std::string& sr{s};
Literal l(sr);
A
(sr) 是const std::string&
但是没有考虑constness,所以编译器考虑了std::string
。这符合您的
template <typename V>
Literal(V val)
{
value = val;
}
所以它使用了这个专业化。如果你有专业
template<>
Literal(std::string val)
编译器会发现这种特化,这可能是您必须做的并使用移动语义。
#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);
}