有人知道为什么the next piece of code不能在Clang 4.0.1上编译吗?
下一个错误:
调用函数'operator <<',该函数在模板中都不可见 定义,也不通过与参数相关的查找找到
有一些文件 test.cpp
#include <vector>
#include <iostream>
namespace Wrapper
{
template<typename T>
struct QuotedStringImpl
{
T const& Value;
explicit QuotedStringImpl(T const& value) :
Value(value)
{
}
};
template<typename T>
inline std::ostream& operator <<(std::ostream& stream, QuotedStringImpl<T> const& rhs)
{
return stream << rhs.Value;
}
template<>
inline std::ostream& operator <<(std::ostream& stream, QuotedStringImpl<std::string> const& rhs)
{
return stream << '"' << rhs.Value << '"';
}
template<typename T>
inline QuotedStringImpl<T> QuotedString(T const& value)
{
return QuotedStringImpl<T>(value);
}
template<typename T>
inline std::ostream& operator <<(std::ostream& stream, std::vector<T> const& value)
{
stream << "[";
std::copy(value.begin(), value.end(), std::ostream_iterator<T>(stream, ", "));
stream << "]";
return stream;
}
} // namespace Wrapper
namespace
{
struct Struct
{
};
std::ostream& operator<<(std::ostream& stream, Struct const&)
{
return stream << "(struct value)";
}
} // namespace
int main()
{
std::vector<Struct> collection(2);
std::cout << Wrapper::QuotedString(collection);
}
此代码已使用msvc 15成功编译。但是我对Clang 4.0.1感到麻烦。根据{{3}}文档,应使用ADL代替实例化。但这对我不起作用。这种行为的原因是什么?
答案 0 :(得分:1)
template<typename T>
inline std::ostream& operator <<(std::ostream& stream, std::vector<T> const& value)
{
stream << "[";
std::copy(value.begin(), value.end(), std::ostream_iterator<T>(stream, ", "));
stream << "]";
return stream;
}
此运算符不在vector
或ostream
或T
(在本例中为anonymous_ns::Struct
)的任何关联命名空间中。因此无法通过ADL找到它。
尝试由以下人员调用
:template<typename T>
inline std::ostream& operator <<(std::ostream& stream, QuotedStringImpl<T> const& rhs)
{
return stream << rhs.Value;
}
位于源中的更早。
通常,在类型的名称空间之外添加运算符是一个糟糕的计划。
作为特定规则,在namespace std
中添加运算符是非法的。
因此,在namespace std
中的类型或模板中添加运算符是一个糟糕的计划。
要解决您的特定问题,只需将以上<<
的定义移到调用点的上方。您的代码现在可以编译。它仍然很脆弱,因为它依赖于向std
中的类型添加运算符。
MSVC无法进行正确的两阶段查找,因此(错误)编译了您的代码。正确的两阶段查找在定义模板的位置进行查找,然后在实例化的位置进行仅ADL 查找。
MSVC会在实例化点进行 full 查找。这违反了C ++标准。