2016-07-29 175 views
5

我想为std::string参数创建一个专门的构造函数,但当我用字符串参数调用它时总是使用另一个。C++构造函数模板专门化

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设计构造函数模板?

+0

你没有申报'value'。这是你会得到的错误:_main.cpp:12:9:错误:'value'未在此范围内声明 value = val; _ –

+0

@HenriqueBarcelos ATL :: CComVariant value'在'Expression'中声明。为了简洁,我只发布了相关的模板内容。 –

+0

我假设'value'是在基类中定义的。 – Bathsheba

回答

6

你没有。

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

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

+0

没有编辑,我没有看到非模板构造函数? – kfsone

+0

对不起,我的答案更清晰。 – Bathsheba

+0

我的困惑是:他只有一个构造函数,它是模板化的,他试图将其专门化,所以编译器的选择在类内模板声明/定义或它的专门化之间 - 非模板过载机会? – kfsone

1

很多时候,当超载是一种解决方案时,人们试图定义完整的专业化。但超载可能是一个更好的解决方案。你的情况,我会创建一个新的构造函数的字符串参数。 请记住,在重载解析中只考虑基本模板。下面这篇文章是一个很好的参考明白这个道理: http://www.gotw.ca/publications/mill17.htm

UPDATE:

总之,要提高我的答案,你可以尝试以下的基本模板的构造函数:

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

按照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&但常量性不考虑,所以编译器认为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

+0

谢谢,这是一个正确的答案!但是,我没有使用gcc工具链的问题。只有在转移到叮当声时,我不得不寻找答案。 – foxfireee