Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:\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 ==========
like image 879
ehremo Avatar asked Jan 17 '13 12:01

ehremo


1 Answers

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.

like image 127
Andy Prowl Avatar answered Oct 24 '22 01:10

Andy Prowl