首页 > 解决方案 > SFINAE:派生类隐藏基类函数依赖于T

问题描述

我编写了 2 个 SFINAE 片段。
他们做同样的事情。
但是,第一个有效,而第二个无效。
为什么?(第二个更类似于我的真实程序。)

此代码有效(http://coliru.stacked-crooked.com/a/50e07af54708f076

#include <iostream>
#include  <type_traits>
enum EN{ EN1,EN2 };
template<EN T1> class B{
    public: template<EN enLocal=T1> typename     
      std::enable_if<enLocal==EN1,void>::type test(){  std::cout<<"1"<<std::endl;}  
    public: template<EN enLocal=T1> typename    
      std::enable_if<enLocal==EN2,void>::type test(){  std::cout<<"2"<<std::endl; }
};

int main(){
    B<EN1> b;
    b.test(); 
}

但是这段代码是不可编译的(http://coliru.stacked-crooked.com/a/28b6afd443b36c7e):-

#include <iostream>
#include  <type_traits>
enum EN{ EN1,EN2 };
class Base{
    public: void test(){
        std::cout<<"1"<<std::endl;
    };
};
template<EN T1> class B : public Base{
    public: template<EN enLocal=T1> 
      std::enable_if_t< enLocal==EN2,void > test(){
        std::cout<<"2"<<std::endl;
    }
};
int main(){
    B<EN1> bEn1; bEn1.test(); //should print 1
    //B<EN2> bEn2; bEn2.test(); //print 2
}

我对 SFINAE 非常陌生,并且仍在通过https://stackoverflow.com/a/50562202/学习它。

标签: c++c++17sfinae

解决方案


这段代码有两个问题:

  1. 调用bEn1.test();bEn2.test();编译器会发现 nametest指的是类中的函数,B而重载函数集将仅包含B::test. 这可以通过将基类中的名称引入派生类来解决:
template<EN T1> class B : public Base{
    public: using Base::test;
  1. 但是,现在非模板函数将优先于模板函数(即使enable_if有效),因此B<EN2> bEn2; bEn2.test();将打印 1。

为了使这项工作再次起作用,您可以引入另一个类似于第一个示例中的重载,它将从基类调用函数,而不是将Base::test名称带入派生类:

public: template<EN enLocal=T1> 
    std::enable_if_t< enLocal!=EN2,void > test(){
       return Base::test();
}

另一种可能的 C++17 风格的解决方法是使用if constexpr类型特征或 SFINAE 来代替:

public: template<EN enLocal = T1> void
test()
{
    if constexpr(EN2 == enLocal)
    {
        std::cout<<"2"<<std::endl;
    }
    else
    {
         Base::test();
    }
}

推荐阅读