Специализация шаблонов для друзей с ++ - PullRequest
2 голосов
/ 02 мая 2019

У меня есть обобщенная структура по модулю, которая называется quotient_ring. Соответствующие биты показаны ниже.

template <typename R = long long>
struct quotient_ring{
    using Q = quotient_ring;
    R x, m;

    ...

    template <typename T>
    friend constexpr std::basic_ostream<T> &operator<< (std::basic_ostream<T> &str, const Q &q){
        return str << '(' << q.x << ")%(" << q.m << ')';
    }
};

Этот оператор << будет печатать что-то вроде 2 mod 7 как (2)%(7). Причина, по которой мне нужны скобки, заключается в том, что тип R может стать очень вложенным. Однако, если R является только арифметическим типом, таким как long long, я хотел бы печатать без скобок. Я обнаружил, что один из способов сделать это заключается в следующем.

template <typename T>
friend constexpr std::basic_ostream<T> &operator<< (std::basic_ostream<T> &str, const Q &q){
    if constexpr (std::is_arithmetic<R>::value) return str << q.x << '%' << q.m;
    else return str << '(' << q.x << ")%(" << q.m << ')';
}

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

1 Ответ

2 голосов
/ 02 мая 2019

Мне, как правило, больше нравится специализация шаблонов, чем переход по признакам типа.

Почему? if constexpr является веткой времени компиляции . Эквивалент SFINAE гораздо менее читабелен.

template <typename R = long long>
struct quotient_ring{
    using Q = quotient_ring;
    R x, m;

    template <typename Char>
    friend constexpr std::enable_if_t<
        std::is_arithmetic_v<R>,
        std::basic_ostream<Char> &
    >
    operator<< (std::basic_ostream<Char> &str, const Q &q){
        return str << q.x << '%' << q.m;;
    }

    template <typename Char>
    friend constexpr std::enable_if_t<
        !std::is_arithmetic_v<R>,
        std::basic_ostream<Char> &
    >
    operator<< (std::basic_ostream<Char> &str, const Q &q){
        return str << '(' << q.x << ")%(" << q.m << ')';
    }
};

int main() {
    quotient_ring<quotient_ring<>> ring{
        {1, 2},
        {3, 4}
    };
    std::cout << ring << '\n'; // (1%2)%(3%4)
}

Могу ли я предложить поставить несколько пробелов в выводе (например, (1 % 2) % (3 % 4)), чтобы сделать его более читабельным?

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