Есть ли способ извлечь параметры по умолчанию для шаблонного класса, зная только неспециализированный шаблонный класс во время компиляции?
Я знаю, как извлечь параметры экземпляра класса шаблона, например:
// Just an example class for the demonstration
template<class A, class B=void>
struct example {};
// Template parameters storage class
template<class...An>
struct args;
// MPL utility that extracts the template arguments from a template class
template<class C>
struct get_args
{
typedef args<> type;
};
template<template<class...> class C, class...An>
struct get_args< C<An...> >
{
typedef args<An...> type;
};
// And the assertion
static_assert(
std::is_same
< args<int,void>,
get_args< example<int> >::type
>::value,
"Check this out"
);
Теперь я хотел бы знать, можно ли использовать decltype
или что-нибудь еще для получения параметров шаблона по умолчанию только из неспециализированного класса шаблона:
// MPL utility that extract template default arguments from a template class
template<template<class...> class C>
struct get_default_args
{
typedef /* what goes here? */ type;
};
// And the assertion
static_assert(
std::is_same
< args<void>,
get_default_args< example >::type
>::value,
"Check this out"
);
На данный момент я только понял, как извлечь количество параметров класса шаблона, а не их значение по умолчанию:
namespace detail {
template< template<class> class >
boost::mpl::size_t<1> deduce_nb_args();
template< template<class,class> class >
boost::mpl::size_t<2> deduce_nb_args();
template< template<class,class,class> class >
boost::mpl::size_t<3> deduce_nb_args();
/* ... and so on ... */
}
// MPL utility that extract the number of template arguments of a template class
template<template<class...> class C>
struct get_nb_args :
decltype(detail::deduce_nb_args<C>()) {};
// And the assertion
static_assert(
get_nb_args< example >::value == 2,
"Check this out"
);
Редактировать
Кажется, что в конце и снова MSVC мешает мне выполнить эту операцию. Что-то вроде следующего вызывает сбой компилятора с фатальной ошибкой C1001: Произошла внутренняя ошибка в компиляторе.
template<template<class...> class D> static
boost::boost::mpl::int_<0> mandatory(D<>*)
{ return boost::boost::mpl::int_<0>(); }
template<template<class...> class D> static
boost::mpl::int_<1> mandatory(D<void>*)
{ return boost::mpl::int_<0>(); }
template<template<class...> class D> static
boost::mpl::int_<2> mandatory(D<void,void>*)
{ return boost::mpl::int_<0>(); }
template<template<typename...> class D> static
boost::mpl::int_<-1> mandatory(...)
{ return boost::mpl::int_<-1>(); }
int check()
{
return mandatory<example>(nullptr);
}
Следующая попытка приводит к ошибке C2976: "D": слишком мало аргументов шаблона
template<template<class,class> class D> static
boost::mpl::int_<0> mandatory2(D<>*)
{ return boost::mpl::int_<0>(); }
template<template<class,class> class D> static
boost::mpl::int_<1> mandatory2(D<void>*)
{ return boost::mpl::int_<0>(); }
template<template<class,class> class D> static
boost::mpl::int_<2> mandatory2(D<void,void>*)
{ return boost::mpl::int_<0>(); }
int check2()
{
return mandatory2<example>(nullptr);
}
Поэтому мне кажется, что независимо от подхода MSVC запрещает программную реализацию класса шаблона с использованием параметров по умолчанию. В свою очередь, мне кажется невозможным использовать технику SFINAE для извлечения: 1. обязательного количества параметров; 2. типы параметров по умолчанию.
Редактировать 2
Хорошо, после нескольких тестов кажется, что это ошибка с MSVC, возникающая при попытке программно создать экземпляр класса шаблона только с использованием аргументов по умолчанию.
Я отправил отчет об ошибке сюда и еще один здесь.
Вот класс свойств, позволяющий проверить, можно ли создать экземпляр класса с использованием заданных параметров шаблона, что не приводит к сбою компилятора, но не оценивается как истинное для классов, создаваемых по умолчанию.
namespace detail {
typedef std::true_type true_;
typedef std::false_type false_;
template< template<class...> class D, class...An >
true_ instantiable_test(D<An...>*);
template< template<class...> class D, class...An >
false_ instantiable_test(...);
}
template< template<class...> class C, class...An >
struct is_instantiable : decltype(detail::instantiable_test<C,An...>(nullptr)) {};
При этом кажется невозможным с помощью MSVC получить тип шаблона, созданный с параметрами по умолчанию. Обычно следующее не компилируется:
template< template<class...> class T, class...An >
struct get_default_v0
{
typedef T<An...> type;
};
namespace detail {
template< template<class...> class T, class...An >
T<An...> try_instantiate();
} // namespace detail
template< template<class...> class T, class...An >
struct get_default_v1
{
typedef decltype(detail::try_instantiate<T,An...>()) type;
};
// C2976
static_assert(
std::is_same< get_default_v0<example,int> , example<int,void> >::value,
"v0"
);
// C2976
static_assert(
std::is_same< get_default_v1<example,int> , example<int,void> >::value,
"v1"
);
void
s впереди, каждый раз пытаясь сбой SFINAE, и если он создает экземпляр, передать его экстрактору аргументов, который извлекает типы после первого n? Опасения: если это не произойдет достаточно рано, SFINAE выйдет из строя. Но это может сработать. ... или то, что @KerrekSB предложил ниже - person Yakk - Adam Nevraumont   schedule 04.03.2015std::vector
). - person Tom Knapen   schedule 04.03.2015