Я хочу написать концепцию C++, которая проверяет, поддерживается ли данный тип библиотекой numeric_limits
или нет. Для этого я написал следующий код:
// test.cc
#include <limits>
template<typename T>
concept UsableType = requires(T v)
{
{std::numeric_limits<T>::min()} -> T;
{std::numeric_limits<T>::max()} -> T;
};
template<UsableType T>
class MyClass
{
private:
T val;
public:
void set(T v)
{
val = v;
}
};
int main()
{
MyClass<int> obj;
obj.set(1);
return 0;
}
Однако, когда я пытаюсь скомпилировать это с помощью g++ -std=c++23 test.cc
, я получаю
test.cc:6:44: error: return-type-requirement is not a type-constraint
6 | {std::numeric_limits<T>::min()} -> T;
| ^
test.cc:7:44: error: return-type-requirement is not a type-constraint
7 | {std::numeric_limits<T>::max()} -> T;
| ^
Почему я получаю эту ошибку, когда numeric_limits
поддерживает int
?
Ошибка связана с тем, что справа от ->
нужно понятие, а не тип. Это должно скомпилировать:
#include <limits>
#include <concepts>
template<typename T>
concept UsableType = requires(T v)
{
{std::numeric_limits<T>::min()} -> std::same_as<T>;
{std::numeric_limits<T>::max()} -> std::same_as<T>;
};
Однако std::numeric_limits<T>
(и его функции-члены min()
и max()
) будут существовать независимо от того, существует ли какая-либо значимая специализация, и они всегда будут возвращать T()
(см. пример онлайн ). Используйте std::numeric_limits<T>::is_specialized, чтобы проверить, действительно ли это имеет какое-либо значение.
template <typename T>
concept UsableType = std::numeric_limits<T>::is_specialized;
Посмотрите онлайн (нет ошибки для int
, ошибка для std::string
)
Я обнаружил, что лучше иметь переменную шаблона, которую можно явно специализировать для пользовательских типов (например, перечислений), которые должны действовать как числа, а затем определить
std::numeric_limits<E>::is_specialized
из переменной шаблона. Это избавляет от необходимости переделывать все это в специализациях, соответствующих резюме,numeric_limits
. И только потом определять концепцию.