Я хочу написать две перегрузки метода, один с аргументами, которые являются экземплярами определенного шаблона, и один для «всего остального».Это работает, когда аргументы являются экземплярами специализации шаблона, но не работает для подклассов специализации шаблона.Например:
template <class T> class Ptr { public: T* ptr; };
class C {};
typedef Ptr<C> CPtr;
class CPtrSub : public CPtr {};
template <class T> void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
template <class T> void foo(const Ptr<T>& a, const Ptr<T>& b) {
std::cout << "ptr\n";
}
int main() {
CPtr p1, p2;
CPtrSub p3, p4;
foo(p1, p2);
foo(p3, p4);
}
Когда я запускаю это, вывод:
ptr
plain
Возможно ли создать перегрузку, выбранную для подклассов шаблона в дополнение к шаблонусамо по себе?
ОБНОВЛЕНИЕ: Питер ответ так близко!Но «конвертируемое в Ptr - не правильный вопрос. Поскольку T никогда не конвертируется в Ptr . Мне нужно, чтобы оно было обусловлено« конвертируемым в Ptr для некоторых V ».
Так что это работает, чтобы избежать специфической специализации CPtr:
template <typename T, typename = std::enable_if<!std::is_convertible<T, CPtr>::value >::type >
void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
Но попытки пойти по пути "преобразуемый в Ptr для некоторых V" приводят к ошибке компиляции (не можетвыводим V):
template <typename T, typename V, typename = std::enable_if<!std::is_convertible_v<T, Ptr<V> > >::value >
void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
Однако я нашел решение, которое работает в моем случае, но, возможно, не полностью. Если я сделаю свой шаблон Ptr наследуемым от какого-то другого класса, я смогу протестировать этот классвместо этого. Этот код:
class PtrBase {};
template <class T> class Ptr : public PtrBase { public: T * ptr; };
class C {};
typedef Ptr<C> CPtr;
class CPtrSub : public CPtr {};
template <typename T, typename = std::enable_if<!std::is_convertible<T, PtrBase>::value >::type >
void foo(const T& a, const T& b) {
std::cout << "plain\n";
}
template <class T> void foo(const Ptr<T>& a, const Ptr<T>& b) {
std::cout << "ptr\n";
}
int main() {
C c1, c2;
CPtr p1, p2;
CPtrSub p3, p4;
foo(c1, c2);
foo(p1, p2);
foo(p3, p4);
}
Производит вывод
plain
ptr
ptr
Таким образом, ответ Питера действительно привел к правильному месту. Было бы все еще хорошо знать, если есть общий ответ, которыйне полагается на базовый класс шаблона.
ЗАКЛЮЧИТЕЛЬНОЕ ПРИМЕЧАНИЕ: некоторые из этих функций метапрограммирования доступны в C ++ 11, C ++ 17 и C ++ 20. Я снизил использование до доступных вещей C ++ 11.