C++ 中的前向声明模板变量

陈浩南*_*陈浩南 8 c++ language-lawyer

前向声明的模板变量会导致 ld 错误。

#include <iostream>
template<class T> extern int a;
template<class T> int a = 1;
int main()
{
    std::cout << a<int> << a<float>;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)
$ LANG=C g++ main.cpp -o main
/usr/bin/ld: /tmp/cccOb25F.o: in function `main':
main.cpp:(.text+0x6): undefined reference to `a<int>'
/usr/bin/ld: main.cpp:(.text+0x1d): undefined reference to `a<float>'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

但是,前向声明变量(无模板)和前向声明模板函数工作正常。

#include <iostream>
extern int a;
int a = 1;
template<class T> int b();
template<class T> int b()
{
    return 2;
}
int main()
{
    std::cout << a << b<int>();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

那么,是否可以使 C++ 中的前向声明模板变量起作用?

编辑

由于clang++工作正常,也许我不小心发现了一个错误g++

编辑2

我发现了大约 2.5 年前的错误报告(这里),这是完全相同的问题。哦,我们需要一个可以阅读 gcc 源代码并修复它的人......

dfr*_*fri 5

打开 GCC 错误报告 83342 -“带有更高定义的外部标记变量模板发出错误”

这是GCC 错误 83342,尚未解决。

无论有意与否,GCC 似乎假设首先extern在给定翻译单元 (TU) 中使用关键字声明的变量模板必须在另一个TU 中定义(因此甚至不在同一个 TU 中查找它)。例如,Clang 没有做出这个假设(并且在同一个 TU 中找到了定义和重新声明)。

template<class T> extern int a;      // extern declaration.
template<class T>        int a = 1;  // definition.
template int a<int>;  // explicit instantiation definition for a<int> specialization.

// Clang: OK
// GCC:
// - error: explicit instantiation of 'a<int>' but no definition available

int main() {}
Run Code Online (Sandbox Code Playgroud)

标准中没有条款允许 GCC 做出上述假设,并且公开的错误报告是有效的。

我们可能会注意到 GCC 接受函数模板的类似且可能更常见的情况:

template<class T> extern void f();    // extern declaration.
template<class T>        void f() {}  // definition.
template void f<int>();  // explicit instantiation definition for f<int>() specialization.

// Clang: OK
// GCC:   OK

int main() {}
Run Code Online (Sandbox Code Playgroud)