Решение 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);
}