C ++ Специализация шаблонов функций для шаблонного базового класса - PullRequest
2 голосов
/ 05 октября 2019

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

Пожалуйста, посмотрите на следующий пример, демонстрирующий проблему:

#include <vector>

struct MyVector : public std::vector<int> {};

struct S {
    template <typename T>
    int make(T value) {
        return 1;
    }

    template <typename T>
    int make(const std::vector<T>& value) {
        return 2;
    }
};

int main() {
    S s;
    // return s.make(std::vector<int>{}); // returns 2, perfekt!
    return s.make(MyVector{}); // returns 1 but should return 2
}

Live: https://godbolt.org/z/PgYkKf

Я искална stackoverflow в течение нескольких часов, но не смог найти правильное решение .. Я благодарен за любые советы!

1 Ответ

3 голосов
/ 05 октября 2019

шаблон специализации функций

Первый заказ бизнеса. Это не специализация. Важно получить это из пути, чтобы найти решение. Это перегрузка. Два шаблона функций перегружают имя make. И разрешение перегрузки определяет, что лучше подходит после синтеза их сигнатур. В вашем случае две сигнатуры, которые может вывести компилятор:

int make(MyVector);
int make(std::vector<int> const&);

Одна - это преобразование идентификатора, в то время как другая требует привязки ссылки к базе, которая по степени конверсии хуже, чем "идентичность". ,Таким образом, выбирается первая перегрузка.

Перед вами есть несколько вариантов:

  1. Предпочитайте псевдоним типа, например using MyVector = std::vector<int>;. Она прямолинейна, точно соответствует второй перегрузке и выберет ее из-за частичного упорядочения шаблонов функций.

  2. Добавьте перегрузку MyVector, которая делегирует:

    int make(MyVector const& v) { return make(static_cast<MyVector::vector const&>(v)); }
    
  3. Используйте более сложную технику для управления разрешением перегрузки. Стандартная библиотека имеет несколько утилит для управления процессом на основе SFINAE . Для этого потребуется изменить первую перегрузку следующим образом:

    template <typename T>
    std::enable_if_t<!std::is_convertible_v<T*, std::vector<int>*>, int>
    make(T value) {
        return 1;
    }
    

    Но этот подход слишком удобен для экспертов и быстро не масштабируется при многих перегрузках шаблона. Сначала я рекомендую два предыдущих подхода.

...