Предположим, у меня есть
#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 ==========
Это похоже на ошибку VC10 для меня, и это не относится в std::string
,
ОШИБКА ИЗОЛЯЦИИ:
Я привел это к следующему примеру:
#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*
, При попытке инициализировать b2
из rvalue
VC10, похоже, не может выбрать оператора преобразования в B
,
И Clang 3.2, и GCC 4.7.2 выбирают оператор преобразования в B
,
СТАНДАРТНЫЕ ПРАВИЛА C ++:
Пункт 8.5 / 16 Стандартных мандатов C ++:
[для этого случая инициализации копирования,] «определяемые пользователем последовательности преобразования, которые можно преобразовать из исходного типа к типу назначения или (когда используется функция преобразования) для ее производного класса нумеруются, как описано в 13.3.1.4, и лучший выбирается с помощью разрешения перегрузки (13.3) «Если мы рассмотрим все доступные последовательности преобразования в нашем примере из типа источника (A
) к типу назначения (B
), то тот, который включает в себя A
пользовательская функция преобразования в char const*
требует в дальнейшем преобразование (сделано через B
конструктор, который принимает char const*
) для того, чтобы достичь тип назначения B
, Таким образом, это на один шаг дольше, чем тот, который использует A
пользовательская функция преобразования в B
(согласно 13.3.3.2), что делает последний предпочтительным.
Это, кажется, подтверждает, что это ошибка VC10.
Других решений пока нет …