为什么clang要求在模板中调用函数之前需要声明函数?

问题描述 投票:2回答:1

我有以下代码示例(可在coliru上在线获得:]

#include <iostream>
#include <utility>

struct Bar {
    int a;
};

template <class T>
void print_arg(const T& arg) {
    std::cout << arg << std::endl;    
}

std::ostream& operator<<(std::ostream& os, const Bar& b) {
    os << b.a;
    return os;
}

template <class T1, class T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& pair) {
    os << "Pair(" << pair.first << ',' << pair.second << ")";
    return os;
}

int main()
{
    auto bar = Bar{1};
    print_arg(bar);
    print_arg(std::make_pair(bar, bar));
    print_arg(std::make_pair(bar, 1));
    print_arg(std::make_pair(0, 1));
}

主要功能的最后一行给我带来了麻烦。使用g ++进行编译可以很好地工作(具有与下面完全相同的选项),我启动可执行文件并按预期打印所有内容。但是,Clang ++给了我以下错误:

$ clang++ -std=c++17 -O2 -Wall -Werror -Wpedantic main.cpp && ./a.out
main.cpp:10:15: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
    std::cout << arg << std::endl;    
              ^
main.cpp:29:5: note: in instantiation of function template specialization 'print_arg<std::pair<int, int> >' requested here
    print_arg(std::make_pair(0, 1));
    ^
main.cpp:19:15: note: 'operator<<' should be declared prior to the call site
std::ostream& operator<<(std::ostream& os, const std::pair<T, T>& pair) {
              ^
1 error generated.

此外,删除最后一行(将其注释掉)会导致Clang ++正确编译所有内容。据我所知,这意味着std::pair<int, int>在质量上与其他参数类型不同。

我的问题是,为什么g ++仍要编译它?更重要的是,为什么clang认为以后再声明operator<<(ostream, pair<Bar, Bar>)是可以的,但是对于operator<<(ostream, pair<int, int>)却不是可以的。是否因为后者仅包括标准类型和基本类型?

对我来说(某种程度上)的逻辑似乎是仅在标准/基本类型上定义函数是UB,但是g ++默默地忽略了它,而clang ++给出了一个看起来很奇怪的错误消息。但是,这对我来说没有太大意义,我找不到相关的标准条款。

Note:我知道向上声明是clang所要求的,但是我不明白为什么。我想在单独的标题中提供print_arg函数,并允许使用该标题的人在使用operator<<时专门使用print_arg

c++ g++ clang++
1个回答
0
投票

查看Language Compatibility : Unqualified lookup in templates部分。它确切地解释了这种情况。

摘要为GCC编译错误代码,而clang遵循标准。

© www.soinside.com 2019 - 2024. All rights reserved.