Something along this line should work:
struct S { static auto create(int) { return new S; } }; struct T { T(int) {} }; struct U {}; template<int N> struct tag: tag<N-1> {}; template<> struct tag<0> {}; class Factory { template<typename C> auto create(tag<2>, int N) -> decltype(C::create(N)) { return C::create(N); } template<typename C> auto create(tag<1>, int N) -> decltype(new C{N}) { return new C{N}; } template<typename C> auto create(tag<0>, ...) { return new C{}; } public: template<typename C> auto create(int N) { return create<C>(tag<2>{}, N); } }; int main() { Factory factory; factory.create<S>(0); factory.create<T>(0); factory.create<U>(0); }
It is based on sfinae scheduling methods and tags.
The basic idea is that you pass the create function of your factory to a set of internal functions. These functions check the functions you are looking for due to the tag and are discarded if the test fails. Due to sfinae, if one of them succeeds, the code compiles and everything works as expected.
Here is a similar solution in C ++ 17:
#include <type_traits> #include <iostream> #include <utility> struct S { static auto create(int) { return new S; } }; struct T { T(int) {} }; struct U {}; template<typename C> constexpr auto has_create(int) -> decltype(C::create(std::declval<int>()), bool{}) { return true; } template<typename C> constexpr auto has_create(char) { return false; } struct Factory { template<typename C> auto create(int N) { if constexpr(has_create<C>(0)) { std::cout << "has create" << std::endl; return C::create(N); } else if constexpr(std::is_constructible_v<C, int>) { std::cout << "has proper constructor" << std::endl; return new C{N}; } else { std::cout << "well, do it and shut up" << std::endl; (void)N; return C{}; } } }; int main() { Factory factory; factory.create<S>(0); factory.create<T>(0); factory.create<U>(0); }
Thanks to @StoryTeller and @ Jarod42 for their help on this difficult morning.
Look at it and launch wandbox .
source share