I need a template function:
template <typename ...Signatures, typename ...Functions> auto make_callable_object (Functions&& ...functions);
which will return the called object. When the called object is called with any signature from the signature, the corresponding functions from the functions should be called.
eg:.
auto co = create_callable_object<void (int), void (std::string), void (std::exception)> ( [] (int i) { std::cout << "int"; }, [] (std::string) { std::cout << "string"; } [] (std::exception) { std::cout << "exception"; } );
should return an object equivalent
struct { void operator() (int) const { std::cout << "int"; } void operator() (std::string) const { std::cout << "string"; } void operator() (std::exception) const { std::cout << "exception"; } };
I created some implementation but it does not compile with clang C ++ 11.
I am not sure if there is an error or a compiler error in my code. I am looking for workarounds, or maybe the best solution to be compiled with both gcc and clang in C ++ 11 mode.
Link Coliru
#include <iostream> #include <tuple> #include <type_traits> #include <functional> #define noexcept #define constexpr #define constexpr14 struct callable_impl_base { // will trigger if called with bad signature template <typename ...Ts> void operator() (Ts...) const { throw std::bad_function_call {}; } }; template <typename Func, typename Base, typename Sig> struct callable_impl; template <typename Func, typename Base, typename R, typename ...Args> struct callable_impl<Func, Base, R (Args...)>: public Base { template <typename FF> constexpr callable_impl (FF&& f, Base&& b) : Base (std::forward<Base> (b)) , func (std::forward<FF> (f)) { } // unhiding method from the base classes. using Base::operator(); constexpr R operator() (Args&& ...args) const { return func (std::forward<Args> (args)...); } constexpr14 R operator() (Args&& ...args) { return func (std::forward<Args> (args)...); } Func func; }; template <typename Sig, typename Func, typename Base> constexpr callable_impl< typename std::decay<Func>::type , typename std::decay<Base>::type , Sig > make_callable_impl (Func&& func, Base&& base) { return { std::forward<Func> (func), std::forward<Base> (base) }; } // Recursion stopper. template <typename ...> constexpr callable_impl_base make_callable () { return {}; } // Strip first Sig and first Func one by one. template <typename Sig, typename ...Sigs, typename F, typename ...Fs> constexpr14 auto make_callable (F&& f, Fs&& ...fs) -> decltype (make_callable_impl<Sig> ( std::forward<F> (f), make_callable<Sigs...> (std::forward<Fs> (fs)...))) { static_assert (sizeof... (Sigs) == sizeof... (Fs), "bad number of args"); return make_callable_impl<Sig> ( std::forward<F> (f), make_callable<Sigs...> (std::forward<Fs> (fs)...)); } using namespace std; struct A {}; struct B {}; int main () { auto x = make_callable<void (const A&), void(B const&), void(int,int,int)> ( [] (A const&) {cout << "A\n";}, [] (B const&) {cout << "B\n";}, [] (int,int,int) { cout << "int,int,int\n"; } ); x (B{}); x (A{}); x (1,2,4); // this must throw because of incompatible signature. try { x (1,2); } catch (std::bad_function_call) { std::cout << "x (1,2) -> got exception (ok)\n"; } }
UPDATE:
I tried another solution and got rid of explicit signatures in the make_callable template parameters. So now the link function is called in this simple way:
int main () { using namespace std; auto co = make_callable ( [] (int) { cout << "int\n"; }, [] (string) { cout << "string\n"; }, [] (int,int) { cout << "int,int\n"; } ); cout << "co(\"str\") -> "; co ("fff"); cout << "co(55) -> "; co (55); cout << "co(55, 44) -> "; co (55, 44);
And here is the Coliru Demo . But I'm still not sure if it is efficient enough or perhaps a much better solution.