【问题标题】:Difference between return value and local variable返回值和局部变量的区别
【发布时间】:2013-01-17 12:37:33
【问题描述】:

假设我有

#include <string>

class A
{
public:
    template<class T>
    operator T();

    A child();
};

void f()
{
    A a;
    std::string s1 = a;            // ok
    std::string s2 = a.child();    // error (line 34)

    s1 = a;           // error (line 36)
    s2 = a.child();   // error (line 37)

}

std::string 构造函数可以采用 char* 或 std::string 引用,这就是赋值不明确的原因。但是为什么我的编译器(VC++10)抱怨第二个赋值而不是第一个呢?

我正在寻找一种方法来优先考虑模板转换运算符而不是重载的构造函数。

我收到以下错误:

1>------ Build started: Project: Plasma4Test, Configuration: Debug Win32 ------
1>  Plasma4Test.cpp
1>d:\bitbucket\vx\projects\plasma4test\plasma4test.cpp(34): error C2440: 'initializing' : cannot convert from 'A' to 'std::basic_string<_Elem,_Traits,_Ax>'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          No constructor could take the source type, or constructor overload resolution was ambiguous
1>d:\bitbucket\vx\projects\plasma4test\plasma4test.cpp(36): error C2593: 'operator =' is ambiguous
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(772): could be 'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(_Elem)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(767): or       'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(const _Elem *)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(762): or       'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(const std::basic_string<_Elem,_Traits,_Ax> &)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          while trying to match the argument list '(std::string, A)'
1>d:\bitbucket\vx\projects\plasma4test\plasma4test.cpp(37): error C2593: 'operator =' is ambiguous
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(772): could be 'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(_Elem)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(767): or       'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(const _Elem *)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(762): or       'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(const std::basic_string<_Elem,_Traits,_Ax> &)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          c:\program files\microsoft visual studio 10.0\vc\include\xstring(707): or       'std::basic_string<_Elem,_Traits,_Ax> &std::basic_string<_Elem,_Traits,_Ax>::operator =(std::basic_string<_Elem,_Traits,_Ax> &&)'
1>          with
1>          [
1>              _Elem=char,
1>              _Traits=std::char_traits<char>,
1>              _Ax=std::allocator<char>
1>          ]
1>          while trying to match the argument list '(std::string, A)'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

【问题讨论】:

  • 这在 Clang 3.2 和 GCC 4.7.2 上都能正常编译。这可能是一个 VC10 错误
  • 嗯。 xvalue vs lrvalue(对吗?)——但不确定这如何导致差异。您能否包含收到的整个错误消息?
  • @Yakk:刚试了一下:“没有构造函数可以采用源类型,或者构造函数重载解析不明确”
  • 是的,看起来像一个 VC 错误。 VC 有时会在模板中出现模板问题。我认为这是一个例子。
  • 好的,不同编译器的行为不同,坏消息。我想我只能接受它行不通。在实践中,我使用成员函数 A::as 而不是隐式转换运算符来避免这个问题。

标签: c++ constructor return-value local-variables conversion-operator


【解决方案1】:

对我来说这似乎是一个 VC10 错误,它与std::string不相关

BUG 隔离:

我把它归结为下面的例子:

#include <string>

class B
{
public:
    B(char const*) { }
    B(B&&) { }
};

class A
{
public:
    operator char* const () { return 0; }
    operator B () { return B(0); }
};

int main()
{
    A a;
    B b1 = a; // fine
    B b2 = A(); // error C2440: 'initializing' : cannot convert from 'A' to 'B'
                // No constructor could take the source type, or constructor
                // overload resolution was ambiguous.
}

B 类有一个移动构造函数和一个采用const char* 的构造函数。当尝试从rvalue 初始化b2 时,VC10 似乎无法选择转换运算符为B

Clang 3.2 和 GCC 4.7.2 都选择转换运算符为B

C++ 标准规则:

C++ 标准第 8.5/16 条规定:

[对于复制初始化的这种情况,]“用户定义的转换序列,可以从源类型转换为目标类型或(当使用转换函数时)到其派生类如 13.3.1.4 所述枚举,并通过重载决议选择最佳的一个(13.3)"

如果我们考虑我们示例中从源类型 (A) 到目标类型 (B) 的所有可用转换序列,那么涉及到 A 的用户定义转换函数到 @ 987654332@ 需要进一步 转换(通过接受char const*B 的构造函数完成)才能到达目标类型 B。因此,它比使用A 的用户定义转换函数到B(根据13.3.3.2)的那一步要长一步,这使得后者更可取。

这似乎证实这是一个 VC10 错误。

【讨论】:

  • 但如果我删除了“operator char* const () { return 0; }”,它会编译。我认为这是一个不同的问题,但毫无疑问是相关的。另一个问题只有 1 个模板功能。我怀疑这与 VC 如何决定实例化模板函数有关。
  • @thang:对,这与它无法转换为B这一事实无关,而是它在复制初始化期间未能选择该转换。它认为两个构造函数都一样好,而采用B&amp;&amp; 的构造函数应该是首选。我试图弄清楚为什么这是真的
猜你喜欢
  • 2021-11-07
  • 2013-01-06
  • 1970-01-01
  • 2022-06-16
  • 2016-01-17
  • 1970-01-01
  • 2015-10-21
  • 2021-10-22
相关资源
最近更新 更多