условное использование декларации - PullRequest
0 голосов
/ 19 мая 2019
#include <iostream>

using namespace std;

template<bool enable, typename T>
struct foo;

template<typename T>
struct foo<false , T>
{
    //nothing
};

template<typename T>
struct foo<true , T>
{
    void say_hello() 
    { 
        cout << "Hello !" << endl;
    }

    protected:

        int m_some_data_when_I_enabled{};
};

template<bool Enable, typename T>
struct bar
    :
    foo<Enable , T>
{
    //And there are lots of functions and members

    //Here I need conditional 'using'
    using foo<Enable , T>::say_hello;

    void say_hello(int different_signature)
    {

    }
};

struct duck {   };

int main(int, char**) {
    bar<true , duck> enabled_bar;
    bar<false , duck> disabled_bar;
}

Выдает ошибку, когда я объявляю бар. Это имеет смысл для меня. Поэтому мне нужно что-то вроде:

template<typename = typename std::enable_if<Enable>::type>
using foo<Enable , T>::say_hello();

Я знаю, что могу решить проблему с помощью специализации 'bar', но в ней есть несколько членов, и в этом случае я бы продублировал множество кодов. Есть ли другой, может быть хитрый, способ?

Ответы [ 2 ]

3 голосов
/ 19 мая 2019

Вы можете объявить удаленный say_hello в своем первом foo, что делает оператор using в bar допустимым.

template<typename T>
struct foo<false , T>
{
    void say_hello() = delete;
};

Здесь - полный пример.

0 голосов
/ 19 мая 2019

Вы можете добавить простую перегрузку пересылки и использовать SFINAE, чтобы условно отключить ее, когда элемент не существует в базовом классе. Как это:

template<typename V = T, typename = decltype(&foo<Enable, V>::say_hello)>
void say_hello() 
{ 
    bar::foo::say_hello();
}

Посмотреть вживую

Нам нужно использовать &foo<Enable, V>::say_hello вместо &foo<Enable, T>::say_hello, чтобы отложить проверку и заставить ее произойти во время подстановки (когда делается попытка вызвать функцию), в отличие от того, что происходит при создании экземпляра bar.

Если элемент не существует, разрешение перегрузки отменяет новую перегрузку (из-за неправильно сформированной замены), как будто ее никогда не существовало.

Но стоит отметить, что это не будет работать для наборов перегрузки (потому что нельзя взять указатель на член набора перегрузки). Он будет работать только в том случае, если вы знаете, что существует только одна перегрузка, в которой указатель на член может быть сформирован однозначно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...