Концепции очень новые. Я примерно на 90% уверен, что следующий способ является правильным, но я не смог заставить его скомпилировать на clang:
template <typename T>
concept Streamable =
requires(std::ostream &os, T value) {
{ os << value } -> std::convertible_to<std::ostream &>;
};
Чтобы обойти ограничения clang, вы может сделать это:
template <typename T>
concept Stream = std::is_convertible_v<T, std::ostream &>;
template <typename T>
concept Streamable =
requires(std::ostream &os, T value) {
{ os << value } -> Stream;
};
Другой подход - определить черту без понятий, а затем определить понятие в терминах черты. Но затем вы жертвуете одним из преимуществ концептов - сообщениями об ошибках.
// This is how we used to do things back in my day
template <typename T, typename = void>
struct is_streamable : std::false_type {};
template <typename T>
struct is_streamable<T, std::enable_if_t<
std::is_convertible_v<
decltype(std::declval<std::ostream &>() << std::declval<T>()),
std::ostream &
>
>> : std::true_type {};
template <typename T>
concept Streamable = is_streamable<T>::value;
Для компиляторов, которые не поддерживают концепты, вы можете просто использовать черту is_streamable
. Вышеприведенное определение - C ++ 17, но с некоторыми изменениями это можно сделать в C ++ 11.
template <typename T, typename = void>
struct is_streamable : std::false_type {};
template <typename T>
struct is_streamable<T, typename std::enable_if<
std::is_convertible<
decltype(std::declval<std::ostream &>() << std::declval<T>()),
std::ostream &
>::value
>::type> : std::true_type {};
Понятия - просто сахар. Понятия дают вам лучшие сообщения об ошибках и их легче написать, чем описанные выше шаблоны. AFAIK, они не позволяют тебе делать то, что ты не мог сделать в C ++ 17.
Я понял, что эта черта может быть немного упрощена. Я снова использую C ++ 11 для обеспечения переносимости.
template <typename T, typename = void>
struct is_streamable : std::false_type {};
template <typename T>
struct is_streamable<T, decltype(
static_cast<std::ostream &>(std::declval<std::ostream &>() << std::declval<T>())
)> : std::true_type {};
Поскольку я снова редактирую ответ, я скажу, что понятия - просто сахар! C ++ 20 большой. Пройдет некоторое время, прежде чем поддержка станет достаточно распространенной, чтобы сделать возможным использование концепций в производстве.