Я не понимаю, почему код ниже печатает struct Value
вместо int
(что подразумевает, что конструктор преобразования преобразует в Value
вместо int
). (Visual C ++ 2012)
Почему это происходит? Почему компилятор полностью игнорирует Value(int)
конструктор?
#include <iostream>
#include <type_info>
using namespace std;
struct Value { Value(int) { } };
struct Convertible
{
template<class T>
operator T() const
{ throw typeid(T).name(); }
};
int main()
{
try { Value w((Convertible())); }
catch (char const *s) { cerr << s << endl; }
}
Еще более странным является этот (на этот раз это только C ++ 11, в GCC 4.7.2):
#include <iostream>
#include <typeinfo>
using namespace std;
struct Value
{
Value(Value const &) = delete;
Value(int) { }
};
struct Convertible
{
template<class T>
operator T() const
{ throw typeid(T).name(); }
};
int main()
{
try { Value w((Convertible())); }
catch (char const *s) { cerr << s << endl; }
}
Который дает:
source.cpp: In function 'int main()':
source.cpp:21:32: error: call of overloaded 'Value(Convertible)' is ambiguous
source.cpp:21:32: note: candidates are:
source.cpp:9:3: note: Value::Value(int)
source.cpp:8:3: note: Value::Value(const Value&) <deleted>
Если конструктор копирования удален, то почему есть двусмысленность ?!
В первом примере Visual Studio неверен; вызов неоднозначен. GCC в режиме C ++ 03 печатает:
source.cpp:21:34: error: call of overloaded 'Value(Convertible)' is ambiguous
source.cpp:21:34: note: candidates are:
source.cpp:9:5: note: Value::Value(int)
source.cpp:6:8: note: Value::Value(const Value&)
Напомним, что конструктор копирования неявно используется по умолчанию. Управляющий пункт 13.3.1.3 Инициализация конструктором [over.match.ctor]:
Когда объекты типа класса инициализируются напрямую […], разрешение перегрузки выбирает конструктор. Для прямой инициализации все функции-кандидаты являются конструкторами класса инициализируемого объекта.
Во втором примере удаленные функции в равной степени участвуют в разрешении перегрузки; они влияют на компиляцию только после устранения перегрузок, когда программа, которая выбирает удаленную функцию, имеет неправильную форму. Мотивирующим примером в стандарте является класс, который может быть построен только из типов с плавающей точкой:
struct onlydouble {
onlydouble(std::intmax_t) = delete;
onlydouble(double);
};
Я пробовал ваш код (только на версии Visual Studio).
Поскольку у вас есть встроенный экземпляр-CTOR, я думаю, что ваш main равен:
int main()
{
try { Value w((struct Value)(Convertible())); }
catch (char const *s) { cerr << s << endl; }
}
Компилятор решил использовать вашу копию CTOR, а не Value (int).
Меняя это на:
int main()
{
try { Value w((int)(Convertible())); }
catch (char const *s) { cerr << s << endl; }
}
На нем напечатано «int».