SFINAE:派生类隐藏基类的功能依赖于T

问题描述 投票:1回答:2

有迹象表明,我编写了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++17 sfinae
2个回答
3
投票

这段代码有两个问题:

  1. 当调用bEn1.test();bEn2.test();编译器会找出名称test是指在课堂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式解决方法利用代替型性状或SFINAE if constexpr

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

1
投票

根据什么是真正的使用情况,您也可以考虑某种形式的标签调度的:

enum class En {
    base, a, b, c
};

template<En Type> void test_impl()
{
    if constexpr (Type == En::base)
        std::cout << "Base\n";
    else if constexpr (Type == En::a)
        std::cout << "1\n";
    else if constexpr (Type == En::b)
        std::cout << "2\n";
    else
        std::cout << "Default\n";
}

struct Base {
    void test() {
        std::cout << "Base - ";
        test_impl<En::base>();  
    }
};

template<En Type>
struct Derived : public Base {
    void test() {
        std::cout << "Derived - ";
        test_impl<Type>();
    }  
};

int main()
{
    Base b;
    b.test();              // -> "Base - Base"
    Derived<En::a> b1;
    b1.test();             // -> "Derived - 1" 
    Derived<En::b> b2;
    b2.test();             // -> "Derived - 2"
    Derived<En::base> b3;
    b3.test();             // -> "Derived - Base"
    Derived<En::c> b4;
    b4.test();             // -> "Derived - Default"
}
© www.soinside.com 2019 - 2024. All rights reserved.