我在 Clang 和 GCC 中发现了错误吗?

Have I found a bug in Clang and GCC?

main.cpp:

#include <iostream>

struct Cls {
    static void some_method() {
        std::cout << __FILE__ << ": " << __LINE__ << std::endl;
    }
};

extern void call_some_method();

void never_caled() {
    Cls::some_method();  // (1)
}

int main() {
    call_some_method();
    return 0;
}

cls.cpp:

#include <iostream>

struct Cls {
    static void some_method() {
        std::cout << __FILE__ << ": " << __LINE__ << std::endl;
    }
};

void call_some_method() {
    Cls::some_method();
}

(1)注释时,call_some_method()将“/home/maxim/CLionProjects/bug/cls.cpp:5”写入std::cout.

当(1)取消注释时,call_some_method()将“/home/maxim/CLionProjects/bug/main.cpp: 5”写入std::cout.

如何实现不同的输出?

__FILE____LINE__ 是由预处理器展开的宏。由于这些宏位于不同的文件中,并且取决于它们在其中使用的文件,因此它们扩展为不同的标记序列。

这意味着您对 Cls::some_method 的定义在不同的翻译单元中是不同的。这违反了单一定义规则 (ODR),除其他外,该规则要求在整个程序中对特定实体只有一个定义。如果有多个定义,那很好,只要这些定义的标记序列在每个翻译单元中都是相同的,并且这些标记在解析时表示相同的东西。

这显然不是你的情况,所以你违反了 ODR,这使得程序格式错误(无需诊断)。这意味着编译器没有义务给你一个错误,但如果它确实产生了一个程序,那么执行该程序会调用未定义的行为(UB)。所以您的程序可以做任何事情,包括生成您所看到的输出。