I have the following class template:
template<typename T=class idType, typename U=class uType>
class f {
std::unordered_map<T::Type, float> id_; // error!
}
I am using the dependency injection framework boost::di
and I therefore need to name my template argument to be able to bind those templates to actual types. I am surprised that I get an error when I try to declare a hashmap using the underlying type of the template idType
. Yes, I would imagine an error if the template argument I use did not have defined a Type
, but I certainly do in my case.
The error is:
error: invalid use of incomplete type ‘class idType’
14 | std::unordered_map<typename T::Type, float> rpc;
| ^~~
example.hpp:9:29: note: forward declaration of ‘class idType’
9 | template<typename T = class idType, typename U = class uType>
CodePudding user response:
They are defined after I include the file containing the example above
Yeah, that's not gonna work.
While templates and class definitions do have some specific leeway in that they can sometimes reference things declared/defined after them, these are very specific cases. The bodies of class member functions can reference other elements of their own class that have not at that point been declared (essentially, the compiler moves the member function definition to just after the class definition).
And templates can reference as-of-yet undefined names... so long as those names are dependent on a template parameter.
The code you've presented uses idType
, which is not a template parameter name. The parameter is T
; idType
is merely the default value of that parameter. If the user provides a different type, your use of idType
will ignore it.
Therefore, the compiler must search for idType
at the point of use within the template, not at instantiation time.
Indeed, the fact that you use idType
as a default value at all also imposes the requirement that type needs to exist at the location of the template definition. You named it, after all; it needs to exist if you name it.