Как отключить функцию-член на основе параметра шаблона класса? - PullRequest
2 голосов
/ 23 сентября 2019

Чтобы проиллюстрировать ситуацию, давайте предположим минимальный пример: шаблонный класс Vector, принимающий свое измерение в качестве нетипичного параметра шаблона.Этот класс будет предоставлять x(), y() (и т. Д.) Методы доступа, когда измерение позволяет это:

template <int N_dimension>
class Vector
{
public:
    // ctors, etc.    
    int &x();

    template <class = std::enable_if_t<(N_dimension>2)>> int &y();

private:
    std::array<int, N_dimension> mData;
};

Тем не менее, это не работает, поскольку enable_if может применяться только к выведены параметры шаблона.

Наш текущий обходной путь выглядит громоздким:

    template <int N=N_dimension, class = std::enable_if_t<(N>2)>> int &y();

Более того, он также требует статического утверждения в определении, чтобы убедиться, что оно защищено от ошибок (посколькутеперь клиентский код может дать явное значение для N, которое не соответствует реальному измерению. Редактировать : Или явное значение для анонимного второго параметра шаблона, как указано SergeyA ).


Есть ли более прямой подход для выражения этого в C ++?

Ответы [ 2 ]

4 голосов
/ 23 сентября 2019

Я бы покончил со SFINAE и просто разделил код на интерфейс и частную реализацию следующим образом:

int& y() {
    return y_impl(std::bool_constant<N > 2>{});
}

private:
int& y_impl(std::true_type ) {
    // impl
}
int& y_impl(std::false_type ) {
    static_assert(N > 2 /* always false */, "Wrong number of dimensions!");
}

Разделение здесь в предположении, что y не компилируется, когда N <= 2,чтобы уменьшить беспорядок сообщений об ошибках.Если это не так, достаточно одного static_assert в y теле.

3 голосов
/ 23 сентября 2019

В C ++ 20 вы можете просто использовать requires, чтобы отменить метод:

template <int N>
class Vector
{
public:
    int &x();
    int &y() requires(N >= 2);

private:
    std::array<int, N_dimension> mData;
};

В предыдущей версии он более подробный:

template <std::size_t N>
class Vector
{
public:
    int &x();

    template <std::size_t M = N, std::enable_if_t<(M >= 2 && M == N), int> = 0>
    int &y();

private:
    std::array<int, N_dimension> mData;
};
...