Функция преобразования шаблона в const-reference

Следующее работает отлично (как и следовало ожидать):

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 & объект этого класса. Это правильное поведение? Я пытался прочитать стандарт, но правила перегрузки меня смущают.

11

Решение

Да, это ошибка в 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;
  • снять квалификацию cv 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,

5

Другие решения


По вопросам рекламы [email protected]