Я перечитывал Шаблон метапрограммирования на С ++ и делать упражнения, содержащиеся в нем, и столкнулись с проблемой. Суть проблемы можно увидеть на этом небольшом примере:
template <class A, class B>
struct C;
template <class A>
struct C<A,A>
{
typedef some_type type;
};
template <class A, class B>
struct C<A*,B>
{
typedef some_other_type type;
};
int main()
{
C<int*,int*> c;
}
Это не скомпилируется, потому что тип c неоднозначен. Компилятор не может сказать, какую специализацию предполагается создать, однако я знаю, что в таком случае я хочу вызвать первую специализацию. Решение, которое я нашел, состоит в том, чтобы переписать его так
template <class A, class B>
struct C;
template <class A, class B>
struct C<A*,B>
{
typedef typename boost::mpl::if_c<boost::is_same<A*,B>::value,
some_type, some_other_type>::type type;
};
Проблема с этим решением заключается в том, что у меня фактически есть частичные специализации для каждого из типов указателей, констант, ссылок и массивов, поэтому мне пришлось добавить эту проверку для каждой специализации в отдельности.
Мой вопрос, таким образом, есть ли какой-нибудь способ иметь хорошие компактные специализации до и каким-то образом настроить его так, чтобы компилятор создавал специализацию
template <class A>
struct C<A,A>
{
typedef some_type type;
};
вместо какой-либо другой специализации в случае двусмысленности?
Для тех, кто интересуется, вопрос, над которым я работаю, это глава 1, вопрос 1
Вы можете добавить другой параметр в ваш базовый шаблон и использовать его для включения / выключения вашей специализации. Например, вы можете иметь:
template< class A, class B, class Enable = void >
struct C;
template< class A >
struct C<A, A, void> {...};
template< class A, class B >
struct C<A*, B, typename boost::disable_if<boost::is_same<A*, B> >::type> {...};
Теперь, если вы хотите обработать константный указатель или что-то еще, вы можете расширить свое состояние в соответствии с чертами типа (is_const
, is_pointer
…)!
Других решений пока нет …