Template compilation error: 'X' does not refer to a value
The Clang compilation error 'X' does not refer to a value
can be misleading.
It means, at that point in the code, Clang is expecting a value, not a type. But the reason for that may be nothing to do with the nature of X
.
It may be that whatever X
is being passed to expects a value rather than a type, i.e. Clang does not think this is a template.
Specifically in this case: template<typename ComponentManager> entity
has been masked by a method in the class – auto entity(int)
. This changes the meaning of entity
, causing an error at the site of the template specialisation, but not at the site of the method which is doing the masking.
GCC gives a much clearer error message in this instance, so it's worth trying a tool like Wandbox to see what different compilers think is wrong with the code.
Leo
Updated on June 15, 2022Comments
-
Leo almost 2 years
I am getting the following error:
'ComponentManager' does not refer to a value
when compiling a subclass which inherits from this parent class:template<typename ComponentManager> class component_collection { protected: int n_components; int n_versions; int first_blank; int last_used; std::vector<std::deque<shared_ptr<entity<ComponentManager>>>> entity_pointers; public: component_collection(int n_c, int n_v) : n_components(n_c), n_versions(n_v), first_blank(0), last_used(0), entity_pointers(n_v, std::deque<shared_ptr<entity<ComponentManager>>>()) // <-- ERROR HERE {} ... };
I am confused as to how I should initialise the
std::vector
withn_v
emptystd::deque
s in the constructor.The sub-class declares a similar
vector
ofdeque
s and compiles / worked as expected (until I added thevector<deque>
to the parent, that is):template<typename ComponentManager> class test_component_collection : public component_collection<ComponentManager> { std::vector<std::deque<int>> values; public: test_component_collection(int n_c, int n_v) : component_collection<ComponentManager>(n_c, n_v), values(n_v, std::deque<int>()) // <-- NO ERROR HERE { } ... };
So it seems this is something to do with this being a container of
std::shared_ptr<entity<ComponentManager>>
, but I don't see why that would be a problem (theentity
header is included, takes a<ComponentManager>
as you would expect, and aComponentManager
is provided when all these classes are used).I am clearly missing something...
Update
Here's the code for
entity
:template<typename ComponentManager> class entity { protected: ComponentManager & component_manager; public: entity(ComponentManager & cm) : component_manager(cm) {} void initialise_components(shared_ptr<entity<ComponentManager>> sp) {} };
Adding this at the top of
component_collection
seems to fix things (the compilation error at least, I've not thoroughly tested the results):template<typename ComponentManager> using entity_ptr_deque = std::deque<shared_ptr<entity<ComponentManager>>>;
And then substituting
entity_ptr_deque<ComponentManager
in as appropriate. This aids readability, so I might leave it in anyway, but it doesn't help understand the error, especially as a minimal example builds fine (see comments).Update 2
Using Wandbox from the comments, I found that my full class didn't compile, while the version edited by @VittorioRomeo did.
Switching from Clang to GCC on Wandbox (I'm using Clang locally) gave a very different error message:
declaration of 'auto component_collection<ComponentManager>::entity(int)' changes meaning of 'entity'
This is a method that was present before I added the
std::vector<std::deque<shared_ptr<entity<ComponentManager>>>> entity_pointers;
and associated constructor update. It of course masks the nameentity
in the class definition, hence the error. Clang's error message pointed somewhere else entirely.