I wanted to start a new project that uses modules, and therefore had to put header-only libraries in a header unit. One of them (sol2) triggered an error (the one in the title) when compiling with Clang. I was able to reproduce the error on a smaller header file, and it turns out that the error only occurs when compiling with Clang: GCC doesn't see the issue when compiling the file as a header unit (the code will be below).
Now, I know that the header unit support in both compilers is experimental. My question is: when it is finished, which behavior will be correct? I was under the impression that static template class member variables should be automatically marked inline, but it looks like Clang disagrees? Am I wrong to expect that variable to be considered inline here, or is Clang wrong?
The test header file in question:
#pragma once
template <typename T> struct S { static int v; };
template <typename T> int S<T>::v = 10;
template <typename T> bool b() {
bool b1 = S<T>::v == 10;
return b1 && true;
}
inline bool B = b<int>();
Precompiled into a header unit with
[clan]g++ -std=c++23 -fmodule-header -xc++-user-header temp.hh
GCC emits no errors. Clang emits:
./temp.hh:5:33: error: non-inline external definitions are not permitted in C++ header units
5 | template <typename T> int S<T>::v = 10;
| ^
./temp.hh:8:21: note: in instantiation of static data member 'S<int>::v' requested here
8 | bool b1 = S<T>::v == 10;
| ^
./temp.hh:12:17: note: in instantiation of function template specialization 'b<int>' requested here
12 | inline bool B = b<int>();
| ^
1 error generated.
No, this member variable is not inline. A similar thing happens with function templates, that are not implicitly inline either (see Does it make any sense to use inline keyword with templates?). A simple modification to a header file reveals a potential multiple definition error:
And yay
P.S. I still can't think of a case where this will work with
inline, though. Sure, the linker error transforms into a compilerduplicate initializationerror, so how do we use our power now? Either way, the variable is not inline here and Clang is right, and GCC apparently is too, because what headers could be imported is apparently implementation defined:Splendid!