SFINAE: Производный класс скрыть функцию базового класса зависит от T - PullRequest
0 голосов
/ 06 февраля 2019

Есть 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/.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

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

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"
}
0 голосов
/ 06 февраля 2019

Этот код имеет две проблемы:

  1. При вызове bEn1.test(); или bEn2.test(); компилятор выяснит, что имя test относится к функции в классе B и множеству перегруженныхфункции будут включать только B::test.Это можно исправить, перенеся имя из базового класса в производный класс:
template<EN T1> class B : public Base{
    public: using Base::test;
Однако теперь не шаблонная функция будет предпочтительнее шаблонной функции (даже когда 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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...