仅当不存在相同的重载时才使重载生效

问题描述 投票:0回答:1

我想做一个简单的

ostream& operator <<
重载,但如果碰巧有另一个重载,我不希望编译器出现任何歧义错误。 这是我能想到的最接近的事情:

template<class Collection>
std::ostream& operator << (std::ostream& stream, const Collection& other)
    requires requires () {
    requires not requires() {stream << other;};//errors here
    other.begin() != other.end();
    ++other.begin();
    stream << *other.begin();

} {...}

上面代码的问题是编译器产生以下错误:

1. Satisfaction of constraint 'requires { requires !requires { stream << other; }; }' depends on itself [constraint_depends_on_self]

我想要的是为任何集合创建一个通用重载,以便轻松输出到控制台(用于调试目的),但是像 std::string 这样的某些集合已经有重载,因此对

std::ostream << std::string
之类的调用是不明确的.

缓解该问题的一个简单方法是专门禁止

std::string
的过载,但我很好奇是否可以为所有现有的过载制定解决方案,而不仅仅是一个特定的过载。

我正在使用 C++20(我不介意 C++23 解决方案)clang 和 gcc 编译器,如果这很重要的话。

附注请不要建议使用包装器或不同名称的函数/运算符。这不是解决问题,这是在逃避问题。

c++ overload-resolution
1个回答
0
投票

最简单的方法是定义两个概念:

  • 可迭代
  • 可串流

然后你必须编写模板并要求满足约束

Iterable<T> && !Streamable<T>

例如:

template <typename T>
concept Iterable = requires(T t)
{
    t.cbegin();
    t.cend();
};

template <typename T>
concept Streamable = requires(std::ostream & os, T t)
{
    os << t;
};

template <typename Collection>
requires (Iterable<Collection> && not Streamable<Collection>)
std::ostream & operator<<(std::ostream & os, const Collection & c)
{
    os << '{';
    for(auto cit = c.cbegin(); cit < c.cend(); ++cit)
    {
        if(cit != c.cbegin())
            os << ", ";
        os << *cit;
    }
    os << "}\n";
    return os;
}

这样,您的重载将仅用于尚未提供运算符的可迭代类型。

实例

© www.soinside.com 2019 - 2024. All rights reserved.