Я использовал выражения SFINAE для проверки, если тип поддерживает operator<<
namespace details
{
template<typename T>
struct sfinae_true : std::true_type
{
};
template<typename T>
sfinae_true<decltype (std::declval<std::ostream &> () << std::declval<T const &> ())> test_for_ostream (int);
template<typename T>
std::false_type test_for_ostream (long);
}
template<typename T>
struct supports_ostream : decltype (details::test_for_ostream<T> (0))
{
};
Что бы я хотел проверить, если этот тип T
можно повторить так, как этот
for (auto && v : vs) {} // vs is T const &
Дилемма заключается в том, что это утверждение, а не выражение, которое делает его несовместимым с decltype
Я думал использовать lambdas для преобразования выражения в выражение, подобное этому
auto x = [] () { for (auto && v : vs) {}; return 0; } (); // vs is T const &
Однако decltype выражений, содержащих лямбды, явно запрещен:
// Won't compile in clang, gcc nor VC++
using x_t = decltype ([] () { for (auto && v : vs) {}; return 0; } ()); // vs is T const &
Поэтому, чтобы дисквалифицировать его для использования в тестовой функции следующим образом:
namespace details
{
template<typename T>
sfinae_true<decltype (
[] () { for (auto && v : std::declval<T const &> ()) ; } ()
)> test_for_container (int);
// Won't work because lambdas aren't allowed in unevaluated contexts
template<typename T>
std::false_type test_for_container (long);
}
template<typename T>
struct is_container : decltype (details::test_for_container<T> (0))
{
};
Итак, у меня закончились идеи, поэтому я подумал, что, возможно, кто-то @Stackoverflow может придумать что-то интересное.
PS.
Я могу несколько понять, почему decltype ([] () {})
не допускается, но decltype ([] () {} ())
всегда должен быть хорошо определен, т.е. void
.