在C++中提前声明模板变量

8
前向声明模板变量将导致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;
}

$ 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

但是,未经模板的前向声明变量和前向声明模板函数可以正常工作。

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

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

编辑:

由于clang++工作正常,也许我意外地发现了g++的一个错误?

编辑2:

我找到了一个关于2.5年前的错误报告(在这里),这正是同样的问题。哦,我们需要一个能够阅读gcc源代码并修复它的人...


1
Clang 看起来很喜欢它。 - chris
你为什么想要将a定义为外部变量? - chtz
2
@AliAskari C++14 引入了变量模板:https://en.cppreference.com/w/cpp/language/variable_template - chtz
@chtz 因为如果我删除 extern,它会报另一个错误 redefinition of ‘template<class T> int a’ - 陈浩南
有趣的事情。我尝试过的所有关于带变量模板的gcc都似乎不起作用??? - Klaus
@Klaus 我使用的是gcc版本10.1.0。 - 陈浩南
1个回答

5

开放GCC Bug报告 83342 - "带有后定义的extern标记的变量模板会产生错误"

这是尚未解决的GCC Bug 83342

看起来,GCC做出了一个假设,即在给定的翻译单元(TU)中首先使用extern关键字声明的变量模板必须有其定义在另一个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() {}

标准中没有任何条款允许做出GCC所做的假设,因此该bug报告是有效的。

我们可以注意到,对于函数模板,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() {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接