// Copyright (C) 2022 johannst #include #include // Helper meta fns. template using enable_if_bool = std::enable_if_t; template using disable_if_bool = std::enable_if_t; template using has_dst = std::integral_constant::value>; // Template meta programming invoke machinery. namespace impl { // Invoke an OPERATION which *USES* a context. template class Op, typename... P, enable_if_bool::HasCtx> = true> typename Op::Return Invoke(const Ctx& C, P... params) { return Op()(C, params...); } // Invoke an OPERATION which uses *NO* context. template class Op, typename... P, disable_if_bool::HasCtx> = true> typename Op::Return Invoke(const Ctx&, P... params) { return Op()(params...); } } // namespace impl // Invoke an OPERATION which *HAS* a DESTINATION with arbitrary number of arguments. template class Op, typename... P, enable_if_bool>> = true> void Invoke(const Ctx& C, P... params) { std::cout << "Invoke " << Op::Name << '\n'; typename Op::Return R = impl::Invoke(C, params...); std::cout << "returned -> " << R << '\n'; } // Invoke an OPERATION which has *NOT* a DESTINATION with arbitrary number of arguments. template class Op, typename... P, disable_if_bool>> = true> void Invoke(const Ctx& C, P... params) { std::cout << "Invoke " << Op::Name << " without destination." << '\n'; impl::Invoke(C, params...); } // Custom context. struct Ctx { void out(const char* s, unsigned v) const { printf("%s%x\n", s, v); } }; // Operations to invoke. template struct OpA { using HasCtx = std::false_type; using Return = int; static constexpr const char* const Name = "OpA"; constexpr Return operator()(int a, int b) const { return a + b; } }; template struct OpB { using HasCtx = std::true_type; using Return = void; static constexpr const char* const Name = "OpB"; Return operator()(const Ctx& C, unsigned a) const { C.out("a = ", a); } }; int main() { Ctx C; Invoke(C, 1, 2); Invoke(C, 0xf00du); return 0; }