// Copyright (C) 2022 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_OVERLOADED_H_ #define DLIB_OVERLOADED_H_ #include <utility> #include <type_traits> namespace dlib { namespace detail { #if __cpp_fold_expressions template<typename ...Base> struct overloaded_helper : Base... { template<typename... T> constexpr overloaded_helper(T&& ... t) noexcept((std::is_nothrow_constructible<Base,T&&>::value && ...)) : Base{std::forward<T>(t)}... {} using Base::operator()...; }; #else template<typename Base, typename ... BaseRest> struct overloaded_helper: Base, overloaded_helper<BaseRest...> { template<typename T, typename ... TRest> constexpr overloaded_helper(T&& t, TRest&& ...trest) noexcept(std::is_nothrow_constructible<Base, T&&>::value && std::is_nothrow_constructible<overloaded_helper<BaseRest...>, TRest&&...>::value) : Base{std::forward<T>(t)}, overloaded_helper<BaseRest...>{std::forward<TRest>(trest)...} {} using Base::operator(); using overloaded_helper<BaseRest...>::operator(); }; template<typename Base> struct overloaded_helper<Base> : Base { template<typename T> constexpr overloaded_helper<Base>(T&& t) noexcept(std::is_nothrow_constructible<Base, T&&>::value) : Base{std::forward<T>(t)} {} using Base::operator(); }; #endif //__cpp_fold_expressions } template<typename... T> constexpr auto overloaded(T&&... t) /*! This is a helper function for combining many callable objects (usually lambdas), into an overload-able set. This can be used in visitor patterns like - dlib::type_safe_union::apply_to_contents() - dlib::visit() - dlib::for_each_type() - dlib::switch_() A picture paints a thousand words: using tsu = type_safe_union<int,float,std::string>; tsu a = std::string("hello there"); std::string result; a.apply_to_contents(overloaded( [&result](int) { result = std::string("int"); }, [&result](float) { result = std::string("float"); }, [&result](const std::string& item) { result = item; } )); assert(result == "hello there"); result = ""; result = visit(overloaded( [](int) { return std::string("int"); }, [](float) { return std::string("float"); }, [](const std::string& item) { return item; } ), a); assert(result == "hello there"); std::vector<int> type_ids; for_each_type(a, overloaded( [&type_ids](in_place_tag<int>, tsu& me) { type_ids.push_back(me.get_type_id<int>()); }, [&type_ids](in_place_tag<float>, tsu& me) { type_ids.push_back(me.get_type_id<float>()); }, [&type_ids](in_place_tag<std::string>, tsu& me) { type_ids.push_back(me.get_type_id<std::string>()); } )); assert(type_ids == vector<int>({0,1,2})); !*/ noexcept(std::is_nothrow_constructible<detail::overloaded_helper<std::decay_t<T>...>, T&&...>::value) { return detail::overloaded_helper<std::decay_t<T>...>{std::forward<T>(t)...}; } } #endif //DLIB_OVERLOADED_H_