Как проверить, что тип T поддерживается iostream, format или to_chars?
Для начала я попробовал использовать std::is_invocable_v:
struct test_iostream {
template <typename T>
std::string operator()(T x, const std::string& low) {
std::ostringstream o;
o << x;
return o.str();
}
}
template <typename F, typename T>
std::string test_cvt_one(testfloat_t x, const std::string &low) {
if constexpr (std::is_invocable_v<F, T, decltype(low)>) {
F f;
std::string str = f(T(x), low);
// ...
}
}
...
low = test_cvt_one<F, std::float128_t>(x, low);
К сожалению это не работает, по крайней мере, clang/gcc/vs считают
f(T(x), low) хорошим выражением, но вычислить его не могут.
Ответы (1 шт):
Автор решения: Serge3leo
→ Ссылка
Удобнее использовать concept (по аналогии с https://ru.stackoverflow.com/a/1579358/430734 и https://ru.stackoverflow.com/a/1579345/430734), так получается короче:
template <typename T>
concept OStreamable = requires(T x, std::ostream& o) {
{o << x} -> std::same_as<std::ostream&>;
};
template<typename T>
concept TO_Charsable =
#if defined(__clang__) && defined(_LIBCPP_VERSION)
// https://github.com/llvm/llvm-project/issues/62282
// См. примечание к P0067R5 в https://libcxx.llvm.org/Status/Cxx17.html
(!std::is_same_v<T, long double> ||
std::numeric_limits<long double>::digits ==
std::numeric_limits<double>::digits) &&
#endif
requires(T x, char* first, char* last) {
{std::to_chars(first, last, x)} -> std::same_as<std::to_chars_result>;
};
template <typename T>
concept Formattable =
#if defined(__clang__) && defined(_LIBCPP_VERSION)
(!std::is_same_v<T, long double> ||
std::numeric_limits<long double>::digits ==
std::numeric_limits<double>::digits) &&
#endif
std::formattable<T, char>;
// Паллиатив: std::is_default_constructible_v<std::formatter<T>>;
Используя, например, так:
struct test_iostream {
template <OStreamable T>
std::string operator()(T x, const std::string& low) {
...
}
};
// или этак:
static_assert(OStreamable<std::string>);
P.S.
К сожалению, в libc++ (проект llvm, бывает, что используется с clang, часто, на FreeBSD/macOS), перегрузки std::formatter<long double> и to_chars() имеются, но некорректные. Поэтому пришлось чистый std::formattable<T, char> немного замутить.