C++ 友元运算符模板特化

c++ friend operator template specialization

我有一个通用的 modulo 结构,称为 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 << ')';
}

我认为这是一个很好的解决方案。但是,我想知道是否可以通过模板专业化来实现同样的目的。我个人更喜欢模板专业化而不是类型特征分支。

I tend to personally like template specialization more than branching on type traits.

为什么? 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))以使其更具可读性?