Forward-declaring template variable in C++

Viewed 178

The forward-declaring template variable will cause ld error.

#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

However, the forward-declaring variable (without template) and the forward-declaring template function works fine.

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

So, is it possible to make the forward-declaring template variable in C++ works?

EDIT:

Since clang++ works fine, maybe I accidentally found a bug of g++?

EDIT2:

I have found a bug report about 2.5 years ago (here), which is exactly the same problem. Oh, we need a guy who could read gcc source and fix it...

1 Answers

Open GCC Bug Report 83342 - "extern marked variable template with later definition emits error"

This is GCC Bug 83342, which is yet to be addressed.

GCC seems to make, whether intentionally or not, the assumption that a variable template first declared with the extern keyword in a given translation unit (TU) must have its definition in another TU (thus not even looking for it in the same TU). E.g. Clang does not make this assumption (and finds the definition and re-declaration in the same 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() {}

There is no clause in the standard that would allow the assumption that GCC makes above, and the open bug report is valid.

We may note that GCC accepts the similar and likely much more common case for function templates:

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() {}
Related