Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <sstream>
- #include <string>
- #include <type_traits>
- #include <utility>
- namespace details {
- namespace impl {
- template<typename T>
- struct has_member_to_string {
- private:
- template<typename U>
- using test_type = decltype(std::declval<U>().to_string());
- template<typename U>
- static std::true_type test(test_type<U>*);
- template<typename U>
- static std::false_type test(...);
- public:
- using type = decltype(test<T>(nullptr));
- };
- using std::to_string;
- template<typename T>
- struct has_non_member_to_string {
- private:
- template<typename U>
- using test_type = decltype(to_string(std::declval<U>()));
- template<typename U>
- static std::true_type test(test_type<U>*);
- template<typename U>
- static std::false_type test(...);
- public:
- using type = decltype(test<T>(nullptr));
- };
- }
- template<typename T>
- using has_member_to_string = typename impl::has_member_to_string<T>::type;
- template<typename T>
- using has_non_member_to_string = typename impl::has_non_member_to_string<T>::type;
- template<typename T>
- using is_convertible_to_string = std::is_convertible<T, std::string>;
- template<typename T>
- using is_first_overload = std::bool_constant<is_convertible_to_string<T>::value>;
- template<typename T>
- using is_second_overload = std::bool_constant<has_member_to_string<T>::value && !is_convertible_to_string<T>::value>;
- template<typename T>
- using is_third_overload = std::bool_constant<has_non_member_to_string<T>::value && !has_member_to_string<T>::value && !is_convertible_to_string<T>::value>;
- template<typename T>
- using is_fourth_overload = std::bool_constant<!has_non_member_to_string<T>::value && !has_non_member_to_string<T>::value &&
- !has_member_to_string<T>::value && !is_convertible_to_string<T>::value>;
- // first overload is for objects which are implicity convertible to std::string
- template<typename T>
- auto as_string(T&& object) -> std::enable_if_t<is_first_overload<T>::value, std::string> {
- return std::forward<T>(object);
- }
- // second overload is for objects with member function 'to_string'
- template<typename T>
- auto as_string(T&& object) -> std::enable_if_t<is_second_overload<T>::value, std::string> {
- return std::forward<T>(object).to_string();
- }
- // third overload is for objects with non-member function 'to_string' (std::to_string or found via ADL)
- template<typename T>
- auto as_string(T&& object) -> std::enable_if_t<is_third_overload<T>::value, std::string> {
- using std::to_string;
- return to_string(std::forward<T>(object));
- };
- // fourth overload is for objects with operator<< with std::ostream
- template<typename T>
- auto as_string(T&& object) -> std::enable_if_t<is_fourth_overload<T>::value, std::string> {
- std::ostringstream stream;
- stream << std::forward<T>(object);
- return stream.str();
- }
- }
- template<typename T>
- std::string as_string(T&& value) {
- return details::as_string(std::forward<T>(value));
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement