【发布时间】: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&& 调用<< 运算符,然后为std::ostream& 调用<< 运算符。
另一方面,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++ 似乎找不到我在代码中定义的第一个 << 运算符。
我的问题是:在这方面哪个编译器是正确的?如果 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