Компилятор не может выводить возвращаемый тип?

102
5

Я пытаюсь использовать ключевое слово decltype для автоматической функции:


struct Thing {
static auto foo() {
return 12;
}
using type_t =
decltype(foo());
};

И я получаю следующую ошибку (gcc 7.4):


<source>:6:25: error: use of 'static auto Thing::foo()' before deduction of 'auto'
decltype(foo());
^
<source>:6:25: error: use of 'static auto Thing::foo()' before deduction of 'auto'

Почему компилятор еще не вывел тип возврата?

спросил(а) 2018-03-14T01:59:00+03:00 1 год, 11 месяцев назад
1
Решение
115

Поскольку для определения класса компилятор сначала определит все имена и типы участников. Тело функции анализируется после этого.


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


В точке компиляция определяется


using type_t = decltype(foo());

Функция foo() тело еще не проанализировано.

В качестве средства защиты вы можете использовать


static auto foo() -> decltype(12) {
return 12;
}

ПРИМЕЧАНИЕ.


Это явление только для класса. Следующий код вне класса будет компилироваться:


auto bar() { return 12; }

using t = decltype(bar());

ответил(а) 2018-03-14T02:10:00+03:00 1 год, 11 месяцев назад
77

Это потому, что a using внутри класса или структуры видит объявление, но не определение членов. Поэтому см. auto, но не видит return 12;.


Если он отличается, это будет опасно, потому что определение членов может использовать определенные типы (using или typedef).

Представьте себе следующее:


struct Thing {
static auto foo() {
return type_t{};
}
using type_t =
decltype(foo());
};

ответил(а) 2018-03-14T02:10:00+03:00 1 год, 11 месяцев назад
50

@liliscent уже объяснил этапы компиляции вашего примера, но здесь есть дополнительное reductio ad absurdum: в теле метода вы можете использовать идентификаторы из того же класса, которые объявлены после метода, потому что тело только переведено после разбора полного определения класса. Представьте себе, что выведенный тип foo был доступен внутри определения Thing. Затем мы сможем законно написать следующее:


struct Thing {
static auto foo() {
return type_t{};
}
using type_t =
decltype(foo());
};

И что теперь должно быть type_t? Аналогично, недопустимо следующее:


struct Thing {
static auto foo() { return bar(); }
static auto bar() { return foo(); }
};

Это происходит не потому, что bar неизвестно в точке, где вступает в действие определение foo, а потому, что его возвращаемый тип еще не был выведен.


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

ответил(а) 2018-03-14T16:17:00+03:00 1 год, 11 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема