#c #g #c -concepts #c 20
#c #g #c -концепции #c 20
Вопрос:
В этом определении концепции:
#include <utility>
template<class Func, class Ret, class... Args>
concept Invokable = requires(Func f) {
{ f(std::declval<Args>()...) } -> Ret;
};
при создании экземпляра, подобного этому:
static_assert(Invokable<decltype([](int){}), void, int>);
gcc-9.0.1 (магистральные) дампы (ну, если быть точным, реализация стандартной библиотеки):
$ g -O2 -std=c 2a -fconcepts -Wall -Wextra -Werror -c tu1.cpp
error: static assertion failed: declval() must not be used!
2204 | static_assert(__declval_protector<_Tp>::__stop,
| ^~~~~~
демонстрация:https://godbolt.org/z/D0ygU4
Неправильно ли отклонять этот код? Если нет, то что я сделал не так? Если да, то где следует сообщить об этой ошибке?
Примечания
Это принято
template<auto f, class... Args>
constexpr auto size_of_return_type = sizeof(f(std::declval<Args>()...));
при создании экземпляра следующим образом:
static_assert(sizeof(int) == size_of_return_type<[](int){ return 0; }, int>);
Demo: https://godbolt.org/z/gYGk8U
Последние состояния проекта C 2a:
[expr.prim.req]/2
Требуемое выражение — это значение типа bool, значение которого описано ниже. Выражения, появляющиеся в теле требования, являются недооцененными операндами.
Ответ №1:
Неправильно ли отклонять этот код?
Да, концепции никогда не оцениваются, о чем свидетельствует цитируемая вами цитата. Это ошибка gcc 68781 и ошибка gcc 82171.
Обратите внимание, что нет причин использовать declval
внутри концепций. Это более просто:
template<class Func, class Ret, class... Args>
concept InvokableR = requires(Funcamp;amp; f, Argsamp;amp;... args) {
{ f(std::forward<Args>(args)...) } -> Ret;
};
declval
существует, потому что вам нужно какое-то выражение определенного типа, и вы не можете просто написать T()
, потому что для этого требуется конструктор по умолчанию. Концепции дают вам эту возможность в качестве первоклассной языковой функции. Все еще нужно forward
, хотя.
Комментарии:
1. Спасибо за ваше замечание о необходимости
std::forward
.