#include <type_traits>
#include <memory>
#include <iostream>
template<class T>
class ObjectMustBeCreatedType : public std::false_type {
// needed for proper static_assert<T> below
};
// default function that has to be specialized, otherwise compiler error
template<class T>
std::shared_ptr<T> CreateObject(const std::string &path) {
static_assert(ObjectMustBeCreatedType<T>::value,
"please specialize this for your class");
}
// SFINAE to detect static T::Create function
template <
typename T,
typename = typename std::enable_if<
std::is_same<
std::shared_ptr<T>,
decltype(T::Create(std::string{}))
>::value
>::type
>
std::shared_ptr<T> CreateObject(const std::string &s) {
return T::Create(s); // if T::Create is found, call it
}
// for this class the SFINAE version should be triggered
// and CreateObject<AutomaticClass> should be instantiated automatically
struct AutomaticClass {
static std::shared_ptr<AutomaticClass> Create(const std::string &s) {
std::cout << "AutomaticClass::Create" << std::endl;
return std::make_shared<AutomaticClass>();
}
};
// for this class CreateObject is manually specialized below
struct ManualClass {
ManualClass(const std::string &s) {
std::cout << "ManualClass constructor: " << s << std::endl;
}
};
// manual CreateObject<ManualClass> specialization
template<>
std::shared_ptr<ManualClass> CreateObject(const std::string &s) {
std::cout << "CreateObject<ManualClass>" << std::endl;
return std::make_shared<ManualClass>(s);
}
int main() {
// this works
CreateObject<ManualClass>("ManualClass test");
// produces compile errors
CreateObject<AutomaticClass>("AutomaticClass test");
return 0;
}