匿名名称空间中类的ADL [英] ADL for class in anonymous namespace

查看:118
本文介绍了匿名名称空间中类的ADL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人知道为什么下一段代码没有在Clang上编译的原因4.0.1?

Does anybody know why the next piece of code isn't compiled on Clang 4.0.1?

下一个错误:

调用函数'operator<<'在模板中都不可见 定义,也不通过依赖于参数的查找找到

call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup

有一些文件 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有麻烦.根据文档,应使用ADL代替实例化.但这对我不起作用.这种行为的原因是什么?

This code is successfully compiled with msvc 15. But I have troubles with Clang 4.0.1. According with this documentation ADL should be applied in place of instantiation. But it doesn't work for me. What is the reason of such behaviour?

推荐答案

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;
}

此运算符不在vectorostreamT(在本例中为anonymous_ns::Struct)的任何关联命名空间中.因此无法通过ADL找到它.

this operator isn't in any associatied namespace of vector or ostream or T (which in this case is anonymous_ns::Struct). So it cannot be found via ADL.

尝试被以下人员调用:

template<typename T>
inline std::ostream& operator <<(std::ostream& stream, QuotedStringImpl<T> const& rhs)
{
    return stream << rhs.Value;
}

位于源中的更早.

通常,在类型的名称空间之外添加运算符是一个糟糕的计划.

As a general rule, adding operators outside of the namespace of a type is a bad plan.

作为特定规则,在namespace std中添加运算符是非法的.

As a specific rule, adding operators into namespace std is illegal.

因此,在namespace std中的类型或模板中添加运算符是一个糟糕的计划.

As a consequence, adding operators to types or templates in namespace std is a bad plan.

要解决您的特定问题,只需将上述<<的定义移到调用点上方.您的代码现在可以编译了.它仍然很脆弱,因为它依赖于将运算符添加到std中的类型.

To fix your specific problem, simply move the definition of the above << above the point where it is called. Your code now compiles. It remains fragile, because it relies on adding operators to types from std.

在线示例.

MSVC无法进行正确的两阶段查找,因此(错误地)它会编译您的代码.正确的两阶段查找在定义模板的位置进行查找,然后在实例化的位置进行仅ADL 查找.

MSVC fails to do proper two-phase lookup, so it (in error) compiles your code. Proper two-phase lookup does a lookup at the point where the template was defined, and then does an ADL only lookup at the point where it is instantiated.

MSVC会在实例化点进行 full 查找.这违反了C ++标准.

MSVC instead does a full lookup at the point where it is instantiated. This is in violation of the C++ standard.

这篇关于匿名名称空间中类的ADL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆