Template compilation error: 'X' does not refer to a value

11,435

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.

Share:
11,435
Leo
Author by

Leo

Updated on June 15, 2022

Comments

  • Leo
    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 with n_v empty std::deques in the constructor.

    The sub-class declares a similar vector of deques and compiles / worked as expected (until I added the vector<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 (the entity header is included, takes a <ComponentManager> as you would expect, and a ComponentManager 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 name entity in the class definition, hence the error. Clang's error message pointed somewhere else entirely.