【问题标题】:Why can compiler only implicitly convert char * to std::string in some cases为什么编译器在某些情况下只能将 char * 隐式转换为 std::string
【发布时间】:2017-05-30 11:12:20
【问题描述】:

这些工作:

struct WithString {
  WithString(std::string){};
};

void takeString(std::string){}

//implicit conversions:
takeString("hello");
WithString("hello");

但这不是:

WithString makeWithString() { return "hello";}

// error: no viable conversion from returned value of type 'const char [6]'...

如果“hello”在前两种情况下被隐式转换为std::string,为什么不能在最后一种情况下呢?请注意,我没有将WithString 构造函数指定为explicit,所以我希望这样的转换。

我可以通过这样做使行为起作用:

struct WithString {
  WithString(std::string){};
  WithString(const char *){};
};

我只是对这种奇怪现象感到好奇。如果我假设一个猜测,我会说这是因为在前两个工作案例中,转换在 const char *std::string 之间,但在错误情况下,这将需要一个 2 转换链,首先来自 @ 987654329@ 到 std::string,然后从 std::stringWithString。所以也许这就是原因,但我不确定。

【问题讨论】:

    标签: c++ implicit-conversion stdstring char-pointer object-construction


    【解决方案1】:

    我会说这是因为在前两个工作情况下,转换是在 const char * 到 std::string 之间,但在错误情况下,这将需要一个 2 转换链,首先来自 const char *到 std::string,然后从 std::string 到 WithString。所以也许这就是原因,但我不确定。

    没错。

    没有你的 const char* 构造函数重载,这个:

    WithString makeWithString() { return "hello";}
    

    需要两个用户定义的隐式转换;一个给std::string,另一个给WithString。这是不可能的。

    不过,这里只有一个隐式转换(到std::string):

    takeString("hello");
    

    这里也是如此,因为随后“转换”为WithString 是明确的:

    WithString("hello");
    

    我可以通过这样做使行为起作用:

    struct WithString {
      WithString(std::string){};
      WithString(const char *){};
    };
    

    是的,这就是你应该做的。

    【讨论】:

      【解决方案2】:

      你的方法:

      WithString makeWithString() { return "hello";}
      

      需要两次转换:隐式的const char *-to-std::string 转换,然后是WithString 对象的构造。 C++ 最多允许其中一种隐式发生。另请参阅此处的讨论:

      Non-const copy constructor and implicit conversions on return value

      【讨论】:

        【解决方案3】:

        阅读 C++ 标准中的implicit conversions 部分。我在 VS 2015 中尝试了以下代码,编译时没有错误。

        #include <string>
        
        struct WithString {
            WithString(std::string) {};
        };
        
        void takeString(std::string) {}
        
        //implicit conversions:
        void someFunc()
        {
            takeString("hello");
            WithString("hello");
            WithString t = "hello";
        }
        
        WithString makeWithString() { return "hello"; }
        

        VS2015 似乎不正确(将 const char* 到字符串的转换视为标准转换)。以下代码应该按照标准工作,但在 VS2015 中会产生错误:

        WithString makeWithString() { return "hello"s; }
        WithString t = "hello"s;
        

        另见copy initialization。在 Notes 中,它明确调用 WithString t = "hello"; 一个错误。

        【讨论】:

        • 如果 MSVS 2015 允许这样做,那就是错误的。我很好奇你认为哪些 C++11、C++14、C++17 特性应该允许这个程序?
        • 确实 MSVS 2015 C++ 允许这样做。我想问题是 const char* 到 std:string 是否是标准转换。如果是,那么它是正确的;如果不是(即用户定义的转换),则不是。对于所有情况,将鼠标悬停在 Visual Studio 中的“hello”上会产生 std::string::basic_string(const char*_Ptr)。
        • 而且,是的,我在copy initialization 下找到了附加说明:复制初始化中的隐式转换必须直接从初始化程序产生 T,例如直接初始化需要从初始化程序到 T 的构造函数的参数的隐式转换。结构 S { S(std::string) {} }; // 可从 std::string 隐式转换 S s("abc"); // OK:从 const char[4] 转换为 std::string S s = "abc"; // 错误:没有从 const char[4] 转换为 S S s = "abc"s; // OK:从 std::string 转换为 S
        • 12.3/4:最多一个用户定义的转换(构造函数或转换函数)被隐式应用于单个值。
        猜你喜欢
        • 2013-01-03
        • 2021-06-01
        • 2010-10-04
        • 2014-08-27
        • 2021-10-19
        • 2010-11-14
        • 2011-02-19
        • 1970-01-01
        相关资源
        最近更新 更多