Неоднозначная частичная специализация шаблона - PullRequest
6 голосов
/ 07 декабря 2010

У меня есть класс черт, который мне нужно специализировать (и частично специализировать) много раз.

Некоторые частичные специализации перекрываются:

template< typename T > struct C { };
template< typename T1, typename T2 > struct TRAIT { };

template< typename T > struct TRAIT< T, T > { };
template< typename T1, typename T2 > struct TRAIT< C<T1>, C<T2> > { };

int main( ) {
    // ERROR! could be both TRAIT<T,T>   [with T = C<int>]
    //                  and TRAIT<T1,T2> [with T1 = T2 = int]
    TRAIT< C<int>, C<int> > foo;
    return 0;
};

Как я могу получить такой же результат с рабочим кодом?

Я сошел с ума от enable_if и is_same, я даже больше не уверен, что это правильный путь ...

Ответы [ 3 ]

6 голосов
/ 07 декабря 2010

Лучшим вариантом для этого, если вы не можете избежать дублирования специализации, является выяснение всех ваших совпадений.Вам нужно будет написать еще одну специализацию для

template< typename T> struct TRAIT< C<T>, C<T> > { };

... но, как все говорили в комментариях, лучше избегать дублирования, если это вообще возможно.Как говорили другие, проблема может заключаться не в перекрывающихся специализациях, а в том, что это не лучший подход для решения вашей проблемы.

1 голос
/ 07 января 2012

Хитрость заключается в создании вспомогательного типа, который сообщит вам, является ли что-то C<Foo> или нет:

template <typename T> struct C {};

template <typename T> struct is_C {
  static bool const value = false;
};
template <typename T> struct is_C<C<T>> {
  static bool const value = true;
};

Вы были на правильном пути с enable_if, но is_same, кажется,тупик:

#include <type_traits>

template <typename T1, typename T2, typename Enabled = void> struct Trait {
  static char const test = 'D'; // default
};

template <typename T> struct Trait<
    T,
    T,
    typename std::enable_if<!is_C<T>::value >::type
> {
  static char const test = 'N'; // non-C
};

template <typename T1, typename T2> struct Trait<
    T1,
    T2,
    typename std::enable_if< is_C<T1>::value && is_C<T2>::value >::type
> {
  static char const test = 'C'; // some C
};

который вы можете легко протестировать сейчас:

#include <iostream>

int main() {
  Trait< C<int>, C<float> > foo1a;
  Trait< C<int>, C<int> > foo1b;
  Trait< int, int > foo2;
  Trait< int, float > foo3;
  std::cout << "Trait<C<int>,C<float>> : " << foo1a.test << std::endl; // prints 'C'
  std::cout << "Trait<C<int>,C<int>> : " << foo1b.test << std::endl; // prints 'C'
  std::cout << "Trait<int,int> : " << foo2.test << std::endl; // prints 'N'
  std::cout << "Trait<int,float> : " << foo3.test << std::endl; // prints 'D'
  return 0;
}

Вы можете легко изменить это, если хотите, чтобы ваша специализация работала только с одним из параметров какC или что угодно.

0 голосов
/ 07 декабря 2010

Попробуйте:

template< typename T > struct C { };
template< typename T1, typename T2 = T1> struct TRAIT { };
                              // ^^^^^^^^^
                              // Default Type is T1

int main( )
{
        TRAIT<C<int> >         foo1;
        TRAIT<C<int>, C<int> > foo2;

        foo1 = foo2;
        return 0;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...