Следующее работает отлично (как и следовало ожидать):
struct X {};
struct A
{
operator X const& ()
{
static const X value{};
return value;
}
};
int main()
{
A a;
X x = a;
}
Но это не так понятно
template<typename T>
struct X {};
struct A
{
template<typename T>
operator X<T> const& ()
{
static const X<T> value{};
return value;
}
};
int main()
{
A a;
X<int> x = a;
}
GCC 4.9 говорит error: conversion from ‘A’ to non-scalar type ‘X<int>’ requested
тогда как у clang 3.4 проблем с этим нет.
Если вы удалите const
или &
из функции преобразования или если вы пишете X<int> const &x = a
тогда GCC тоже счастлив.
Таким образом, GCC не может найти функцию преобразования, только если целевой тип const &
в шаблонный класс, и вы запрашиваете преобразование в неconst &
объект этого класса. Это правильное поведение? Я пытался прочитать стандарт, но правила перегрузки меня смущают.
Да, это ошибка в GCC. Это почти точно основной DR976, единственное отличие состоит в том, что в их примере тип назначения не является классом:
struct F {
template<class T>
operator const T&() { static T t; return t; }
};
int main() {
F f;
int i = f; // ill-formed
}
Как и в вашем примере, clang принимает, а gcc отклоняет этот пример, независимо от выбранной стандартной версии диалекта.
Обратите внимание, что пункт, измененный этим DR (14.8.2.3 [Temp.deduct.conv]) не делает различий между классом и типом назначения, не относящимся к классу, поэтому разрешение этого DR в равной степени относится и к вашему коду.
В соответствии с измененным пунктом 14.8.2.3 компилятор должен:
P
тип возвращаемого значения шаблона функции преобразования, как X<T> const &
, а также A
, требуемый тип результата, как X<int>
;P
, давая X<T> const
;P
, давая X<T>
;T
как int
,Я бы порекомендовал подать отчет об ошибке на https://gcc.gnu.org/bugzilla/ ссылаясь на этот DR.
Поскольку в вашем случае вы конвертируете в тип класса, есть обходной путь:
X<int> x1 = a; // fails
X<int> x2(a); // OK
X<int> x3 = X<int>(a); // also OK
При прямой инициализации рассматриваются конструкторы типа назначения (8.5p16); конструктор копирования по умолчанию X<int>
принимает параметр типа X<int> const&
, в который, как мы уже видели, gcc с удовольствием конвертирует a
,