I'm trying to get a demo code working to show auto registration with the help of ODR use (I've only learned about this in the last day so forgive me if I'm not using that correctly).
This is the interesting bits of the code
template <const bool*>
struct OdrUse {};
bool Register(const char *) {return true;}
template <typename T>
struct Registered {
static bool registredInInit; // If 'const' is added, clang does not accept the code as well.
static constexpr OdrUse<®istredInInit> odrUser{};
};
template<typename T> // If defined after 'Class', both gcc and clang accept the code.
bool Registered<T>::registredInInit = Register(T::NAME);
struct Class : Registered<Class> {
static constexpr const char* NAME = "ZIP";
};
int main() {
}
Lot of the code has been copied from https://www.cppstories.com/2018/02/factory-selfregister/
I'm getting this error when compiling
<source>: In instantiation of 'bool Registered<Class>::registredInInit':
<source>:9:27: required from 'struct Registered<Class>'
<source>:15:16: required from here
<source>:13:51: error: incomplete type 'Class' used in nested name specifier
13 | bool Registered<T>::registredInInit = Register(T::NAME);
| ^~~~
Compiler returned: 1
Looking at the error, why does the compiler need RegisteredInFactory<ZipCompression> fully defined to access kFactoryName ?
The fix seems to merely be (based on original question):
Live
[EDIT: version with new code snippet]:
Live
registredInInithas to be initialized after declaringClassso that gcc seeClassmembers. But I'm failing to see why it would be a requirement? I'm acknowledging that a more detailed answer is still required. It might be easier by trying to reproduce the issue with a smaller example. Maybe some answer there: c++ template code order parsing/CRTP An hypothesis:At this point
Classis only declared, and is still an incomplete type as gcc rightly says. It also triggers an instanciation ofRegistered<Class>which, in turn, requires initialization of its static members, which callsRegister(NAME)but Class is still incomplete at this time and NAME unknown. Thus gcc would be right, clang and msvc wrong (which I found strange). In general CRTP is working when you are calling base member function from the inherited class, after its definition. So these functions are instantiated only after the inherited class being a complete class. Am I wrong? NB With this snippet, it is not anymore a classical CRTP as the inherited class is not a template but I think that the explanations still hold.[EDIT]
Another way to fix is to let
Classtrigger the init. Here is this solution implemented in @yeputons example, which is more readable:Live Demo
When
LocalRegisteris initialized,Classis a complete type, the call toClass::Register();, triggers the call to ::Register(NAME) where NAME is properly defined.