#include <concepts>
#include <iostream>
#include <string>
#include <type_traits>
// *** before: ***
// a requirement on a template argument was written with enable_if, and
// a wrong type gave pages of errors from deep inside the body
template <class T>
typename std::enable_if<std::is_integral<T>::value, T>::type doubledOld(
T value) {
return value + value;
}
// *** in version C++20: ***
template <std::integral T>
T doubled(T value) { return value + value; }
// a concept of one's own: anything that can be sent to a stream
template <class T>
concept Printable = requires(const T& value, std::ostream& out) {
{ out << value } -> std::same_as<std::ostream&>;
};
void show(const Printable auto& value) { std::cout << value << "\n"; }
// the same requirement in the long form
template <class T>
requires std::floating_point<T>
T half(T value) { return value / 2; }
int main() {
std::cout << doubledOld(21) << " " << doubled(21) << "\n";
// doubled(1.5); <- error, and the message names the constraint itself
show(42);
show(std::string("text"));
std::cout << half(3.0) << "\n";
}