Difference between return value and local variable

Suppose I have

#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)

}

The std::string constructor can take either a char* or an std::string reference, which is why the assignment is ambiguous. But why does my compiler (VC++10) complain about the second assignment but not the first?

I am looking for a way to give precedence to the template conversion operator rather than the overloaded constructor.

I get the following errors:

1>------ Build started: Project: Plasma4Test, Configuration: Debug Win32 ------
1>  Plasma4Test.cpp
1>d:bitbucketvxprojectsplasma4testplasma4test.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:bitbucketvxprojectsplasma4testplasma4test.cpp(36): error C2593: 'operator =' is ambiguous
1>          c:program filesmicrosoft visual studio 10.0vcincludexstring(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 filesmicrosoft visual studio 10.0vcincludexstring(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 filesmicrosoft visual studio 10.0vcincludexstring(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:bitbucketvxprojectsplasma4testplasma4test.cpp(37): error C2593: 'operator =' is ambiguous
1>          c:program filesmicrosoft visual studio 10.0vcincludexstring(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 filesmicrosoft visual studio 10.0vcincludexstring(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 filesmicrosoft visual studio 10.0vcincludexstring(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 filesmicrosoft visual studio 10.0vcincludexstring(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 ==========

It seems like a VC10 bug to me and it is not related to std::string .

BUG ISOLATION:

I brought it down to the following example:

#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.
}

Class B has a move constructor and a constructor which take a const char* . When trying to initialize b2 from an rvalue , VC10 seems to fail to select the conversion operator to B .

Both Clang 3.2 and GCC 4.7.2 select the conversion operator to B .

C++ STANDARD RULES:

Paragraph 8.5/16 of the C++ Standard mandates:

[for this case of copy-initialization,] "user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3)"

If we consider all the available conversion sequences in our example from the source type ( A ) to the destination type ( B ), then the one which involves A 's user-defined conversion function to char const* requires a further conversion (done through B 's constructor that accepts a char const* ) in order to reach the destination type B . Therefore, it is one step longer than the one that uses A 's user-defined conversion function to B (per 13.3.3.2), which makes the latter preferable.

This seems to confirm that it is a VC10 bug.

链接地址: http://www.djcxy.com/p/11732.html

上一篇: 我怎样才能得到给定字符手动设置的字形?

下一篇: 返回值和局部变量之间的区别