没有前向声明的嵌套函数模板实例在 GCC 上编译,但不在 clang 上编译

Dan*_*nra 6 c++ language-lawyer

以下内容不能在 clang 中编译,但可以在 GCC ( Godbolt )中编译:

template <typename K, typename V>
std::ostream& operator<< (std::ostream& o, const std::map<K, V>& map)
{
    const char* sep = "{";
    for (const auto& x : map)
    {
        o << sep << "{" << x.first << ", " << x.second << "}";
        sep = ", ";
    }
    return o << "}";
}

template <typename T>
std::ostream& operator<< (std::ostream& o, const std::vector<T>& vec)
{
    const char* sep = "{";
    for (const auto& x : vec)
    {
        o << sep << x;
        sep = ", ";
    }
    return o << "}";
}

// Usage

int main()
{
    std::map<int, std::vector<int>> t = {{1, {2, 3}}, {4, {5}}};
    std::cout << t << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

谁是对的?

顺便说一句,我知道它是 UB,但是将两个模板定义放入其中也namespace std会使代码在 clang 上编译。

借用的代码是否可以为模板类型定义 operator<<?

son*_*yao 3

铿锵是对的。您应该移动之前的定义的operator<<声明。std::vectoroperator<<std::map

非限定名称查找中,

(强调我的)

对于模板定义中使用的依赖名称,查找将被推迟,直到模板参数已知为止,此时 ADL 检查with external linkage (until C++11)从模板定义上下文以及模板实例化上下文中可见的函数声明,而非 ADL 查找仅检查with external linkage (until C++11)从模板定义上下文中可见的函数声明(换句话说,在模板定义之后添加新函数声明不会使其可见,除非通过 ADL)。