Я не думаю, что это возможно переносимым / надежным способом.
Если вы заинтересованы в регистрации только во время компиляции, я предлагаю сделать Manager
класс шаблона, в котором параметры шаблона являются зарегистрированнымитипов.
Я имею в виду ... если вы пишете пользовательские черты типа следующим образом
template <typename, typename ...>
struct typeInList;
template <typename T0, typename T1, typename ... Ts>
struct typeInList<T0, T1, Ts...> : public typeInList<T0, Ts...>
{ };
template <typename T0, typename ... Ts>
struct typeInList<T0, T0, Ts...> : public std::true_type
{ using type = T0; };
template <typename T0>
struct typeInList<T0> : public std::false_type
{ };
template <typename ... Ts>
using typeInList_t = typename typeInList<Ts...>::type;
или (как предложено Deduplicator (спасибо!)) более компактным способом
// ground case: in charge only when `typename...` variadic list
// is empy; other cases covered by specializations
template <typename, typename...>
struct typeInList : public std::false_type
{ };
template <typename T0, typename T1, typename ... Ts>
struct typeInList<T0, T1, Ts...> : public typeInList<T0, Ts...>
{ };
template <typename T0, typename ... Ts>
struct typeInList<T0, T0, Ts...> : public std::true_type
{ using type = T0; };
template <typename ... Ts>
using typeInList_t = typename typeInList<Ts...>::type;
вы можете использовать его для включения / выключения SFINAE createDerived()
следующим образом
template <typename ... Ts>
struct Manager
{
template <typename T>
typeInList_t<T, Ts...> createDerived ()
{ return T(); }
};
и hasRegisterDerivedMethod
можно записать следующим образом
template <typename, typename>
struct hasRegisterDerivedMethod;
template <typename ... Ts, typename T>
struct hasRegisterDerivedMethod<Manager<Ts...>, T>
: public typeInList<T, Ts...>
{ };
К сожалению, этоработает во время компиляции, но не во время выполнения, поэтому, если вам нужно решение, которое работает как во время компиляции, так и во время выполнения, это решение не для вас.
Ниже приведен полный рабочий пример
#include <iostream>
template <typename, typename ...>
struct typeInList;
template <typename T0, typename T1, typename ... Ts>
struct typeInList<T0, T1, Ts...> : public typeInList<T0, Ts...>
{ };
template <typename T0, typename ... Ts>
struct typeInList<T0, T0, Ts...> : public std::true_type
{ using type = T0; };
template <typename T0>
struct typeInList<T0> : public std::false_type
{ };
template <typename ... Ts>
using typeInList_t = typename typeInList<Ts...>::type;
template <typename ... Ts>
struct Manager
{
template <typename T>
typeInList_t<T, Ts...> createDerived ()
{ return T(); }
};
struct IBase { };
struct Derived1 : public IBase{ };
struct Derived2 : public IBase{ };
template <typename, typename>
struct hasRegisterDerivedMethod;
template <typename ... Ts, typename T>
struct hasRegisterDerivedMethod<Manager<Ts...>, T>
: public typeInList<T, Ts...>
{ };
int main ()
{
Manager<Derived1> myManager;
// whoops, forgot to register Derived2!
Derived1 d1 = myManager.createDerived<Derived1>();
//Derived2 d2 = myManager.createDerived<Derived2>(); // compilation error!
std::cout << std::boolalpha;
std::cout << "Derived1 check = "
<< hasRegisterDerivedMethod<decltype(myManager), Derived1>::value
<< std::endl; // print true
std::cout << "Derived2 check = "
<< hasRegisterDerivedMethod<decltype(myManager), Derived2>::value
<< std::endl; // print false
}
Не по теме: вместо
static const bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
можно написать
static constexpr bool value { type::value };