【问题标题】:Compilation issue with a custom stream derived from std::ostream从 std::ostream 派生的自定义流的编译问题
【发布时间】:2021-05-30 13:29:52
【问题描述】:

最近我写了一些代码来创建一个从std::ostream 派生的自定义流。 它使用 clang++ 12.0 编译,而使用 g++ 10.1 编译失败。

在这两种情况下,我都使用 g++ 附带的 libstdc++。此外,我为两个编译器指定了以下参数:-std=c++20 -Wall -Wextra -Wpedantic

下面的代码是最小的可重现示例:

#include <ostream>
#include <vector>

template <typename T> std::ostream& operator<<(std::ostream& s, const std::vector<T>&) 
{
    return s;
}

struct CustomStream : std::ostream {};

template <typename T> CustomStream&& operator<<(CustomStream&& s, const T& v) 
{
    static_cast<std::ostream&>(s) << v;
    return std::move(s);
}

int main() 
{
    CustomStream() << std::vector<int>{};
}

这段代码在使用 clang++ 编译时,根本不会发出任何警告,而且执行的操作对我来说似乎是合乎逻辑的。即它首先为CustomStream&amp;&amp; 调用&lt;&lt; 运算符,然后为std::ostream&amp; 调用&lt;&lt; 运算符。 另一方面,g++ 给出了以下错误消息,它基本上列举了所有失败的模板推导:

In file included from /usr/include/c++/10/iostream:39,
                 from main.cpp:1:
/usr/include/c++/10/ostream: In instantiation of ‘struct std::__is_insertable<std::basic_ostream<char>&, const std::vector<int>&, void>’:
/usr/include/c++/10/type_traits:138:12:   required from ‘struct std::__and_<std::__is_convertible_to_basic_ostream<CustomStream>, std::__is_insertable<std::basic_ostream<char, std::char_traits<char> >&, const std::vector<int, std::allocator<int> >&, void> >’
/usr/include/c++/10/type_traits:143:12:   required from ‘struct std::__and_<std::__not_<std::is_lvalue_reference<CustomStream> >, std::__is_convertible_to_basic_ostream<CustomStream>, std::__is_insertable<std::basic_ostream<char, std::char_traits<char> >&, const std::vector<int, std::allocator<int> >&, void> >’
/usr/include/c++/10/ostream:773:5:   required by substitution of ‘template<class _Ostream, class _Tp> typename std::enable_if<std::__and_<std::__not_<std::is_lvalue_reference<_Tp> >, std::__is_convertible_to_basic_ostream<_Ostream>, std::__is_insertable<typename std::__is_convertible_to_basic_ostream<_Tp>::__ostream_type, const _Tp&, void> >::value, typename std::__is_convertible_to_basic_ostream<_Tp>::__ostream_type>::type std::operator<<(_Ostream&&, const _Tp&) [with _Ostream = CustomStream; _Tp = std::vector<int>]’
main.cpp:16:40:   required from here
/usr/include/c++/10/ostream:747:11: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘const std::vector<int>’)
  746 |       __void_t<decltype(declval<_Ostream&>()
      |                         ~~~~~~~~~~~~~~~~~~~~
  747 |           << declval<const _Tp&>())>>
      |           ^~~~~~~~~~~~~~~~~~~~~~~~
... (stripped)

因此,g++ 似乎找不到我在代码中定义的第一个 &lt;&lt; 运算符。 我的问题是:在这方面哪个编译器是正确的?如果 g++ 是对的,我还有一个问题:我做错了什么?

我们将不胜感激。

注意:我故意使用右值。如果我用左值替换它们,如下所示:

template <typename T> CustomStream& operator<<(CustomStream& s, const T& v) 
{
    static_cast<std::ostream&>(s) << v;
    return s;
}

int main() 
{
    CustomStream s;
    s << std::vector<int>{};
}

然后clang++和g++都接受代码。

【问题讨论】:

    标签: c++ g++ operator-overloading clang++ ostream


    【解决方案1】:

    不确定为什么不同的编译器会产生不同的结果,但显然它与 ostream 中的following template function 冲突:

    为避免这种情况,您可以将代码包装到自己的命名空间中并享受 ADL 的魔力:

    #include <ostream>
    #include <vector>
    
    namespace CS
    {
        template <typename T>
        std::ostream &operator<<(std::ostream &s, const std::vector<T> &)
        {
            return s;
        }
    
        struct CustomStream : std::ostream
        {
        };
    
        template <typename T>
        CustomStream &&operator<<(CustomStream &&s, const T &v)
        {
            static_cast<std::ostream &>(s) << v;
            return std::move(s);
        }
    }
    int main()
    {
        CS::CustomStream() << std::vector<int>{};
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多