传递派生类时调用重载函数模板的正确实例

问题描述

假设我有一个课程模板

template <class Ta>
struct Base {};

并且我已经写了一些重载的函数模板:

template <class T1,class T2>
void f(Base<T1>&,T2){
    std::cout << "1" << std::endl;
}
template <class T1,Base<T2>&){
    std::cout << "2" << std::endl;
}

当我调用函数时:

    Base<float> base1;
    Base<float> base2;
    f(base1,1);
    f(base1,base2);

我完全符合我的期望:

1
2

一切都很好,但是现在我想创建一个派生类:

template <class Ta,class Tb> 
struct Derived : Base<Ta> {};

突然之间,当我在派生类的实例上运行相同的代码时:

    Derived<float,int> derived1;
    Derived<float,int> derived2;
    f(derived1,1);
    f(derived1,derived2);

我得到不同的结果:

1
1

显然,编译器会解释T2=Derived<Ta,Tb>,而不会将替代重载解释为具有更高的特异性。

向编译器澄清的最佳方法是,将对f(derived1,derived2)的调用解释为对f(Base<T1>,Base<T2>)的调用?


完整minimal example

#include <iostream>

template <class Ta>
struct Base {};

template <class Ta,class Tb> 
struct Derived : Base<Ta> {};


template <class T1,Base<T2>&){
    std::cout << "2" << std::endl;
}

int main()
{
    Base<float> base1;
    Base<float> base2;
    f(base1,base2);
    Derived<float,derived2);
}

解决方法

您可以使用SFINAE限制一个重载:

由于您的Base是模板,因此需要自定义特征(可能使用其他std::is_base_of):

template <template <typename> class C,typename T>
std::true_type is_template_base_of_impl(const C<T>*);

template <template <typename> class C>
std::false_type is_template_base_of_impl(...);

template <template <typename> class C,typename T>
using is_template_base_of = decltype(is_template_base_of_impl<C>(std::declval<const T*>()));
template <class T1,class T2,std::enable_if_t<!is_template_base_of<BaseClass,T2>::value,int> = 0>
void f(Base<T1>,T2){
    std::cout << "1" << std::endl;
}
template <class T1,class T2>
void f(Base<T1>,Base<T2>){
    std::cout << "2" << std::endl;
}

Demo

,

Jarod42的答案使我研究了条件编译解决方案,并使用std::is_base_of找到了有效的解决方案。但是,由于在这个示例中Base是模板,因此该解决方案需要创建Base的非模板父类:

struct Base2 {};

template <class Ta>
struct Base : Base2 {};

如果这样做,其余的解决方案将变得更加简单:

template <class T1,std::enable_if_t<!std::is_base_of<Base2,Base<T2>){
    std::cout << "2" << std::endl;
}

Demo

但是,这仅在您拥有Base的控制权时才有效,而我认为Jarod42的答案在一般情况下适用。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...