почему сопоставление типов шаблонов в C ++ не совпадает со ссылкой на базовый класс, как я могу сделать так, чтобы сопоставление с базовым классом соответствовало? - PullRequest
0 голосов
/ 30 декабря 2018

Вот мой программный код C ++

#include <iostream>
#include <memory>
using namespace std;

template <typename T>
struct A { T x; };

template <typename T>
struct B:A<T> {  };

template <typename T>
void func(const A<T>& t) {
    cout<<"2"<<endl;
}

template <typename T>
void func(const T& t) {
    cout<<"1"<<endl;
}

int main() {
    B<int> b;
    func(b);
}

, и он печатает 1.Но я ожидаю, что вызов функции печатает 2.Почему B<int>b соответствует const T& вместо const A<T>&.И как я могу сделать это, чтобы соответствовать const A<T>&?

Ответы [ 2 ]

0 голосов
/ 30 декабря 2018

Диспетчеризация тегов.

Сначала мы напишем черту, чтобы определить, есть ли у шаблона шаблон в качестве базы:

namespace details {
  template<template<class...>class Z>
  struct htb {
    template<class...Ts>
    constexpr std::true_type operator()(Z<Ts...>*){return {};}
    constexpr std::false_type operator()(...){return {};}
  };
}
template<template<class...>class Z, class X>
constexpr inline auto has_template_base = details::htb<Z>{}((X*)nullptr);

Теперь мы можем использовать нашу новую черту для пометки диспетчеризации:

namespace details{
  template <typename T>
  void func(std::true_type,const A<T>& t) {
    std::cout<<"2"<<std::endl;
  }

  template <class T>
  void func(std::false_type,const T& t) {
    std::cout<<"1"<<std::endl;
  }
}

template <typename T>
void func(const T& t) {
  details::func(has_template_base<A,T>,t);
}

Живой пример .

0 голосов
/ 30 декабря 2018

Решение 1

Вы можете использовать std::enable_if и параметры шаблонного шаблона для лучшего соответствия функции, например:

#include <iostream>
#include <memory>
#include <type_traits>

using namespace std;

template <typename T>
struct A { T x; };

template <typename T>
struct B:A<T> {  };

template <template <typename...> typename T, typename ...Args, typename = std::enable_if_t<std::is_base_of_v<A<Args...>, T<Args...>>>>
void func(const T<Args...>& t) {
    cout<<"2"<<endl;
}

template <typename T>
void func(const T& t) {
    cout<<"1"<<endl;
}


int main() {
    B<int> b;
    func(b);
    func(5);
}

Однако это работает, только если Aпринимает те же параметры шаблона, что и T.Так что если ваш B изменится на экс.

template <typename T, typename U>
struct B : A<T> {}

это больше не будет работать.

Решение 2

На основании ответа Якка вы можете создать черту типа, которая является более общей,Это решение не имеет ограничений на параметры своего шаблона, как это делает решение 1.

namespace detail 
{
    template <template <typename...> typename Base>
    struct template_base_detector
    {
        template <typename... Args>
        constexpr std::true_type operator()(Base<Args...>*);
        constexpr std::false_type operator()(...);
    };
} 

template <template <typename...> typename Base, typename T>
struct is_template_base_of 
    : decltype(std::declval<detail::template_base_detector<Base>>()((T*)nullptr)) {};

// since C++ 14
template <template <typename...> typename Base, typename T>
constexpr bool is_template_base_of_v = is_template_base_of<Base, T>::value;

В зависимости от версии c ++ вы можете использовать различные подходы для использования этой черты.

C ++ 17

Пожалуй, самое компактное решение.Начиная с C ++ 17 constexpr if операторы разрешены, что позволяет нам определить только один func:

template <typename T>
void func(const T& t) 
{
    if constexpr (is_template_base_of_v<A, T>)
        cout << 2 << endl;
    else
        cout << 1 << endl;
}

C ++ 11 и 14

Мы должны вернуться к диспетчеризации тегов:

namespace detail 
{
    template <typename T>
    void func(std::true_type, const T& t) 
    {
        std::cout << 2 << endl;
    }

    template <typename T>
    void func(std::false_type, const T& t) 
    {
        std::cout << 1 << endl;
    }
}

template <typename T>
void func(const T& t) 
{
    detail::func(is_template_base_of<A, T>{}, t);
}
...