C ++ 11隐式转换

时间:2014-06-16 10:52:53

标签: c++ c++11 implicit-conversion

#include <string>

struct String
{
    template<typename T> operator T*() { return 0; }
    operator std::string() { return ""; }
};

int main()
{
    String myStr;

    std::string str1(myStr); // ambiguous, error C2668

    std::string str2 = myStr; // error C2440:
    // 'initializing' : cannot convert from 'String' to
    // `std::basic_string<char,std::char_traits<char>,std::allocator<char>>',
    // No constructor could take the source type,
    // or constructor overload resolution was ambiguous

    const std::string& rStr = myStr; // Ok, but why?
}

我正在使用VS 2013.

问题:

  1. 为什么str1str2的定义会导致不同的编译错误?

  2. 据我所知,当创建rStr时,首先创建一个临时字符串对象,然后rStr将引用临时字符串。但是,为什么创建临时对象不会导致编译错误? tmpstrN之间是否有任何不同?

1 个答案:

答案 0 :(得分:8)

第一个定义std::string str1(myStr);确实是不明确的:

std::string str1(myStr.operator char*());
// or
std::string str1(myStr.operator std::string());

所以这个初始化由于模糊而失败。

这与

基本相同
void foo(char const*);
void foo(std::string);

foo(myStr); // ambiguous

只需要一个用户定义的转换,然后调用一个函数(对于第一个定义,函数是构造函数)。两种转换都是可行的,也不是另一种转换的子集,所以两者都具有相同的等级。


第二个定义std::string str2 = myStr;实际上很好。只允许通过构造函数或转换函数将一个用户定义的转换转换为 std::string,而不是两者都允许。所以只有std::string str2 = myStr.operator std::string();是可行的。

string str2 = expr;不属于expr类型时,请注意string要求expr 转换为std::string 。然后使用生成的临时值通过复制/移动来初始化str2

string str2 = string(expr);
//            ~~~~~~ implicit

因此,右侧的转换必须直接将转换为std::string,否则您需要一个由两个用户定义的转换链来初始化临时:(UDC = User) - 定义转换)

string str2 = string(expr);
// resolved as:
string str2 = expr.operator string();        // fine: one implicit UDC
string str2 = string(expr.operator char*()); // error: two UDCs

例如,exprchar const*通过operator char*然后通过转换构造函数到std::string需要一个由两个用户定义的转换链=>&gt;不可行。如果我们尝试使用operator char*()转换,我们需要额外的构造函数隐式构造函数调用,以使RHS成为string

这与string str1( expr )不同,expr不需要将隐式转换为string可能必须转换为初始化字符串构造函数的参数。从{em>可能转换的 str1直接初始化expr不是(n隐式)转换本身,而只是函数调用。没有创建额外的临时性:

string str1( expr );
// resolved as:
string str1( expr.operator string() ); // fine
string str1( expr.operator char* () ); // fine

在使用启用语言扩展编译时,拒绝此第二个定义。如果没有语言扩展,这种初始化在VS2013 Update 2中就可以了。


第三个遵循不同的初始化方案。据我所知,在这种情况下它应该像第二个一样。语言扩展似乎只适用于第二种,但似乎不适用于第三种语言。