Подтвердить что ты не робот

Можно ли использовать значение параметра напрямую (не его тип, а значение самого себя) в синтаксисе типа возвращаемого типа возврата

Рассмотрим минимальный пример:

template <int>
struct bar { };

int main() 
{
    [](auto i) -> bar<i> { return {}; };
}

Или даже:

template <int>
struct bar {};

template <class I>
auto foo(I i) -> bar<i> {}

clang компилирует обе формы без проблем, но gcc обнаруживает, что действия недействительны (пример 1), (пример 2)

Вопрос может выглядеть глупо, однако тип параметра может иметь перегруженный оператор преобразования constexpr (в этом случае тип i выводится из значения, переданного в lambda/foo в int в constexpr), и в этом случае он было бы довольно удобно не принуждать к обходу, чтобы получить доступ к нему напрямую...

4b9b3361

Ответ 1

Это похоже на ошибку gcc. Я сообщил об этом как о проблеме # 80242.


gcc жалуется на достоверность i как аргумент шаблона:

ошибка: аргумент шаблона 1 недействителен


Я следил за грамматикой С++ из trailing-return-type до template-argument, который должен быть constant-expression:

шаблон аргументов:

  • константа-выражение < -
  • тип-идентификатор
  • ID-выражение

Тогда возникает реальный вопрос: "i действительный constant-expression?" .

Я думаю, что ответ "да" , потому что §8.20.4 [выражение. Const] говорит:

Преобразованное константное выражение типа T представляет собой выражение, неявно преобразованное в тип T, где преобразованное выражение является константным выражением, а последовательность неявного преобразования содержит только:

  • пользовательские преобразования,

[...]

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

Существует последовательность неявных преобразований, которая, начиная с i, будет вызывать преобразованное константное выражение, которое является постоянным выражением. Дано:

template <int>
struct bar { };

template <class I>
auto foo(I i) -> bar<i> { }

int main()
{
    foo(std::integral_constant<int, 1>{}); // (0)
}
  • В контексте вызова функции в (0) аргумент i является экземпляром std::integral_constant<int, 1>.

  • std::integral_constant предоставляет constexpr пользовательское преобразование в базовый value_type.

  • Преобразованные выражения констант явно разрешают пользовательские преобразования, как показано выше в §8.20.4 [выражение. Const].

  • std::integral_constant::operator value_type() вернет аргумент шаблона non-type 1. Это основное постоянное выражение, поскольку оно не нарушает ни одно из правил, указанных в §8.20.2 [expr.const].

  • Следовательно, преобразованное константное выражение является константным выражением.

Ответ 2

Я считаю, что оба примера неверны. На основе стандартной формулировки 5.20 Константные выражения [expr.const]/p2.7:

2 Условное выражение e является выражением постоянной константы если оценка e, следуя правилам абстрактного машина (1.9), оценила бы одно из следующих выражений: j

...

- преобразование lvalue-to-rvalue (4.1), если оно не применяется к:

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

Как в CLANG, так и в GCC, если вы устанавливаете шаблоны, вы получите ошибку, основанную на формулировке выше. Я считаю, что, поскольку в примерах не поддерживается шаблон, диагностика не требуется, поэтому оба компилятора верны.