繁体   English   中英

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();
}

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

如何正确地为std::string专门化这个构造函数模板?

你没有。

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

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

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

A (sr)是const std::string&但是不考虑const std::string& ,所以编译器认为是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);
}

http://ideone.com/eJJ5Ch

很多时候,当重载是一种解决方案时,人们会尝试定义完全专业化。 但过载可能是一个更好的解决方案。 在您的情况下,我将使用string参数创建一个新的构造函数。 请记住,在重载解析中只考虑基本模板。 以下文章是理解这一想法的一个很好的参考: http//www.gotw.ca/publications/mill17.htm

更新:

无论如何,为了改进我的答案,你可以尝试以下基本模板构造函数:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM