C++11 隐式转换

标签 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有什么不同吗?

最佳答案

第一个定义,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 为 < em>转换为 std::string。然后使用生成的临时文件通过复制/移动来初始化 str2:

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

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

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

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

这与 string str1( expr ) 不同,其中 expr 不需要隐式转换为 string。它可能必须转换为初始化字符串构造函数的参数。 str1possibly converted expr 直接初始化不是(n 隐式)转换本身,而只是一个函数调用。没有创建额外的临时文件:

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

在使用启用的语言扩展 编译时拒绝第二个定义。没有语言扩展,这个初始化在 VS2013 Update 2 中没问题。


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

关于C++11 隐式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24242040/

相关文章:

c++ - 计算浮点余数的最佳方法

c++ - 自动扣除失败并显示消息 "inconsistent deduction for auto return type"

string - Scala 中的条件隐式函数

Excel 错误地将范围转换为日期,如何避免?

c++ - 为什么我在 QtCreator 中收到 undefined reference 错误?

c++ - 不确定 C++ 中的常量函数是什么

c++ - 编译 mpg321 需要 libid3tag - 但已安装 libid3tag

c++ - 通过右值引用获取参数的所有权

arrays - Scala 数组映射函数文档 (PSSQ #1​​)

java - C++抽象类的多重继承