#pragma once #include #include #include namespace Meta { template using void_t = void; // Evaluate to false unless this template is specialized for T // TODO: Once we move to C++17, make the template take a generic "auto..." parameter pack template class Template> struct is_instantiation_of : std::false_type {}; // If a set of template arguments that produce T exists, evaluate to true template class Template> struct is_instantiation_of, Template> : std::true_type {}; // Specialized variant of the above to deal with the std::array template argument list template class Template> struct is_instantiation_of2 : std::false_type {}; template class Template> struct is_instantiation_of2, Template> : std::true_type {}; template constexpr auto is_std_tuple_v = is_instantiation_of::value; template constexpr auto is_std_array_v = is_instantiation_of2::value; /// Produce a structure that inherits all given Base classes template struct inherited : Bases... { }; /** * Turn the given template template argument in a type, such that it can be * passed to standard type functors like std::enable_if without having to * evaluate the template with any particular arguments */ template class Temp> struct delay { template using eval = Temp; }; /// Conditionally selects one of the two given templates depending on the given boolean template class OnTrue, template class OnFalse> struct MetaConditional { template using eval = typename std::conditional_t, delay>::type::template eval; }; template constexpr auto is_class_v = std::is_class::value; template constexpr auto is_base_of_v = std::is_base_of::value; template constexpr auto tuple_size_v = std::tuple_size::value; template constexpr auto is_same_v = std::is_same::value; namespace detail { template struct CHECK_EQUALITY_VERBOSELY_DEFAULT_ERROR { static_assert(NoError, "Given integers are not equal!"); }; } /** * Helper structure for asserting that the compile-time constants A and B * are equal. If they aren't, the type Error will be instantiated, which * is supposed to abort compilation due to a static_assert failure. * * The error message can be customized by passing an own Error template, which * is expected to have a static_assert fail if its instantiated with a "true" * argument. This is useful to give helpful error messages instead of cryptic * "5 != 3" messages. */ template class Error = detail::CHECK_EQUALITY_VERBOSELY_DEFAULT_ERROR> struct CHECK_EQUALITY_VERBOSELY { // Force Error to be instantiated and error out if A!=B // If A==B, use sizeof to form the value "true". static constexpr bool value = sizeof(Error); }; template decltype(auto) invoke(F&& f, Args&&... args) noexcept(noexcept(std::forward(f)(std::forward(args)...))) { return std::forward(f)(std::forward(args)...); } //template //using typeof_foo = decltype(std::declval().foo); /*template class Templ, typename ArgsTuple, typename = void_t> struct is_valid_impl : std::false_type {}; template class Templ, typename... Args> struct is_valid_impl, Templ> : std::true_type {}; template class Templ, typename... Args> using is_valid = is_valid_impl>; */ template class Templ, typename... Args> struct is_valid_impl : std::false_type {}; template class Templ, typename... Args> struct is_valid_impl>, Templ, Args...> : std::true_type {}; template class Templ, typename... Args> using is_valid = is_valid_impl; /*template> struct is_valid_call_impl : std::false_type {}; template struct is_valid_call_impl()(std::declval()...))>> : std::true_type {}; template static constexpr auto is_valid_call(F&& f, Args&&... args) { return is_valid_call_impl::value; }*/ /*template struct invoke_result; template struct invoke_result()(std::declval()...)), F, Args...> { using type = decltype(std::declval()(std::declval()...)); }*/ template using invoke_result = std::invoke_result; //template //using invoke_result_t = invoke_result::type; template using invoke_result_t = typename invoke_result::type; /** * Helper class for calling a function such that its arguments are evaluated in * sequential order. This couldn't easily be achieved otherwise, since the * C++ standard doesn't guarantee evaluation order for function arguments. * It does guarantee left-to-right evaluation in brace-initialization (cf. * C++ standard draft n4296 ([dcl.init.list] (8.5.4.4))), though, which is why * this class exists. * * Usage example: * char f(int a, int b); * int num = 0; * CallWithSequentialEvaluation { f, ++num, ++num }; * * Note that the return type cannot easily be deduced and hence must be * specified manually. * * TODO: Chances are this behavior isn't implemented in all major * compilers. The following may be affected: * * MSVC 2015 Update 3 (untested) * * GCC 7.1.1 (seems to be working for nontrivial cases) * Symptoms of this issue are that IPC command arguments may be * loaded in the wrong order. */ template class CallWithSequentialEvaluation { Result result; public: template CallWithSequentialEvaluation(F&& f, Args&&... args) : result(std::forward(f)(std::forward(args)...)) {} Result GetResult() && { return std::move(result); } }; template CallWithSequentialEvaluation(F&&, Args&&...) -> CallWithSequentialEvaluation>; // Specialization for void template<> class CallWithSequentialEvaluation { public: template CallWithSequentialEvaluation(F&& f, Args&&... args) { std::forward(f)(std::forward(args)...); } }; template struct function_traits; template struct function_traits { using args = std::tuple; }; template struct function_traits { using args = std::tuple; }; template constexpr std::underlying_type_t to_underlying(Enum value) noexcept { return static_cast>(value); } template constexpr Enum next_enum(Enum value, std::underlying_type_t n = 1) noexcept { return Enum { Meta::to_underlying(value) + n }; } } // namespace Meta