Перегрузка метода C ++ аргументами шаблона: как заставить это работать для подкласса шаблона? - PullRequest
0 голосов
/ 19 октября 2018

Я хочу написать две перегрузки метода, один с аргументами, которые являются экземплярами определенного шаблона, и один для «всего остального».Это работает, когда аргументы являются экземплярами специализации шаблона, но не работает для подклассов специализации шаблона.Например:

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.

1 Ответ

0 голосов
/ 19 октября 2018

Я думаю, что вы должны погрузиться в некоторые шаблоны метапрограммирования здесь.Проблема в том, что ваша первая перегрузка является «лучшим» соответствием для подклассов Ptr<T>, потому что она не требует какого-либо преобразования.Вы можете исправить это, удалив его из набора перегрузки.Что-то вроде:

template <class T> std::enable_if_t<!std::is_convertible_v<T, Ptr<T>>
foo (const T& a, const T& b)
{
    /* details */
}
...