Вывод типа возврата для функций-друзей в классе

Вот небольшой эксперимент с вычет типа возврата для функций друзей в классе (используя Clang 3.4 SVN и g ++ 4.8.1 с std=c++1y в обоих случаях), что не задокументировано в связанном рабочем документе

#include <iostream>

struct A
{
int a_;
friend auto operator==(A const& L, A const& R)
{
return L.a_ == R.a_; // a_ is of type int, so should return bool
}
};

template<class T>
struct B
{
int b_;
friend auto operator==(B const& L, B const& R)
{
return L.b_ == R.b_; // b_ is of type int, so should return bool
}
};

using BI = B<int>;

int main()
{
std::cout << (A{1} == A{2}) << "\n";    // OK for Clang, ERROR for g++
std::cout << (BI{1} == BI{2}) << "\n";  // ERROR for both Clang and g++
}

Живой пример.

Вопрос: поддерживается ли автоматический возврат типа возврата для функций-друзей в классе в C ++ 14?

30

Решение

Что касается других ответов: мы имеем дело с n3638 здесь, и как это включено в последние проекты C ++ 1y.

Я использую 9514cc28 из GitHub хранилище комитета, который включает в себя некоторые (незначительные) исправления / изменения в n3638 уже.

N3638 позволяет явно:

struct A {
auto f(); // forward declaration
};
auto A::f() { return 42; }

И, как мы можем сделать вывод из [dcl.spec.auto], где указана эта функция, даже следующие будут допустимы:

struct A {
auto f(); // forward declaration
};

A x;

auto A::f() { return 42; }

int main() { x.f(); }

(но об этом позже)

Это принципиально отличается от любого задний обратный тип или поиск зависимого имени, как auto f(); предварительная декларация, аналогичная struct A;, Это должно быть завершено позже, до того, как оно будет использовано (до того, как потребуется тип возврата).

Кроме того, проблемы в OP связаны с внутренними ошибками компилятора. Недавняя сборка clang ++ 3.4 trunk 192325 Debug + Asserts не компилируется, так как утверждение не выполняется при анализе строки return L.b_ == R.b_;, Я не проверял с последней версией g ++ на данный момент.


Является ли пример ОП законным по отношению к n3638?

Это немного хитрое ИМО. (Я всегда имею в виду 9514cc28 в этом разделе.)

1. Где разрешено использовать `auto`?

[Dcl.spec.auto]

6 Программа, которая использует auto или же decltype(auto) в контексте, явно не разрешенном в этом разделе, является некорректным.

2 Тип заполнителя может появиться с декларатором функции в Децл-спецификатор-сл, Тип Спецификатор-сл, преобразование-функция-идентификатор, или же задний обратный тип, в любом контексте, где такой декларатор действителен.

/ 5 также определяет некоторые контексты, но они здесь не имеют значения.

Следовательно, auto func() а также auto operator@(..) как правило, допускается (это следует из состава объявления функции как T D, где T имеет форму Децл-спецификатор-сл, а также auto это Тип Спецификатор).


2. Разрешено ли писать `auto func ();`, то есть объявление, которое не является определением?

[dcl.spec.auto] / 1 говорит

auto а также decltype(auto) типа спецификаторы обозначить тип заполнителя, который будет заменен позже, либо путем вычитания из инициализатора, либо путем явной спецификации с задний обратный тип.

и / 2

Если объявленный тип возврата функции содержит тип заполнителя, тип возврата функции выводится из return операторы в теле функции, если таковые имеются.

Хотя это не так эксплицитно разрешить декларацию вроде auto f(); для функции (то есть объявления без определения) из n3638 и [dcl.spec.auto] / 11 ясно, что она предназначена для явного, а не явного запрета.


3. Как насчет функций друзей?

Пока пример

struct A
{
int a_;
friend auto operator==(A const& L, A const& R);
}

auto operator==(A const& L, A const& R)
{ return L.a_ == R.a_; }

должен быть хорошо сформирован. Интересной частью сейчас является определение функции друга внутри определения A, то есть

struct A
{
int a_;
friend auto operator==(A const& L, A const& R)
{ return L.a_ == R.a_; } // allowed?
}

На мой взгляд, это разрешено. Чтобы поддержать это, я приведу название поиска. Поиск имени внутри определения функций, определенных в объявлении функции-друга, следует за поиском имени функций-членов в соответствии с [basic.lookup.unqual] / 9. / 8 того же раздела определяет неквалифицированный поиск имен, используемых внутри тел функций-членов. Одним из способов, которым имя может быть объявлено для использования, является то, что оно «должно быть членом класса X или быть членом базового класса X (10.2) «. Это позволяет широко известным

struct X
{
void foo() { m = 42; }
int m;
};

Обратите внимание, как m не заявлено до его использования в foo, но это член X,

Из этого я делаю вывод, что даже

struct X
{
auto foo() { return m; }
int m;
}

позволено. Это поддерживается clang ++ 3.4 trunk 192325.
Поиск имени требует интерпретировать эту функцию только после struct было завершено, также рассмотрим:

struct X
{
auto foo() { return X(); }
X() = delete;
};

Точно так же тело функций-друзей, определенных внутри класса, может быть интерпретировано только после завершения класса.


4. Как насчет шаблонов?

В частности, как насчет friend auto some_function(B const& L) { return L.b_; }?

Во-первых, нагнетаемого имя класса B эквивалентно B<T>см. [temp.local] / 1. Это относится к текущая реализация ([Temp.dep.type] / 1).

ID-выражение L.b_ относится к член текущей инстанции (/ 4). Это также зависимый член текущего экземпляра — это дополнение сделано после C ++ 11, см. DR1471, и я не знаю, что об этом думать: [temp.dep.expr] / 5 утверждает это ID-выражение является не зависит от типа, и, насколько я вижу, [temp.dep.constexpr] не говорит, что это зависит от значения.

Если имя в L.b_ не зависит, поиск имени будет следовать правилам «обычного поиска имени» согласно [temp.nondep]. Иначе, это будет весело (поиск зависимых имен не очень хорошо указан), но, учитывая, что

template<class T>
struct A
{
int foo() { return m; }
int m;
};

принимается большинством компиляторов, я думаю, что версия с auto должен быть действительным тоже.

Есть также раздел о друзьях шаблонов в [temp.friend], но IMO, он не проливает свет на поиск имени здесь.


Также см это очень актуальное обсуждение на isocpp-форуме.

10

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

Других решений пока нет …

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