0

I have a declaration of a class in an .hpp file:

template <typename Ressource, typename Identifier> class RessourceHolder {
public:
  void load(Identifier id, const std::string& filename);

  Ressource& get(Identifier id);
  const Ressource& get(Identifier id) const;


private:
  void insert(Identifier id, std::unique_ptr<Ressource> resource);


private:
  std::map<Identifier, std::unique_ptr<Ressource>> mRessourceMap;
};

template class RessourceHolder<sf::Texture, Textures::ID>;
typedef RessourceHolder<sf::Texture, Textures::ID> TextureHolder;

which include explicit instantiation for RessourceHolder<sf::Texture,Textures::ID>.

And I have the implementation of it in a separate .cpp file. The problem is the following : Later on I define a const TextureHolder and it raises the following error :
undefined reference to `RessourceHolder<sf::Texture, Textures::ID>::get(Textures::ID) const
Why?

EDIT :
As asked, the point where the problem arise (hpp file):

class Agent{
  public :
  Agent(TextureHolder const& textures);
  void setTexture();
  const TextureHolder& mTextures;
  private :
  sf::Sprite mSprite;
};

(cpp file)

Agent::Agent(TextureHolder const& textures) : mTextures(textures){
  setTexture();
}
void Agent::setTexture(){
  mSprite.setTexture(mTextures.get(toTextureID(mType)));
}

When I remove the const specifier in agent, I don't have an error anymore

Shirenn
  • 1
  • 1
  • You are explicitly instantiating the class template but not its functions. I believe you would have to do the explicit instantiation of the class _after all its methods have been defined_ in order for those to be also explicitly instantiated along with the class. – Max Langhof Feb 27 '19 at 14:02
  • There are other possible problems with the code you show, but for now you need to edit your question to include a [mcve] to show us. How do you define your member functions? Also please take some time to read about [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Feb 27 '19 at 14:02
  • 1
    [Possible duplicate](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file). Please include a [mcve]. The error message is just what I would expect from the code you show, there is no definition of the method and unless you show it I wont believe you :P – 463035818_is_not_an_ai Feb 27 '19 at 14:02
  • 1
    As for your other possible problem, an explicit instantiation definition can only exists *once* in all of your program. If the definition is in a header file then it will be defined in all [*translation units*](https://en.wikipedia.org/wiki/Translation_unit_(programming)) where that header file is included. – Some programmer dude Feb 27 '19 at 14:04
  • PS: Resource only has one "s". – Max Langhof Feb 27 '19 at 14:06
  • Oups, french mistake – Shirenn Feb 27 '19 at 14:12
  • Works here: [Demo](https://onlinegdb.com/HyyqgQ4LV) – Jarod42 Feb 27 '19 at 14:37

1 Answers1

0

On a basic level, instantiating a template class only instantiates the class definition, not the definitions of the member functions.

Now, explicit instantiation of a class template does also explicitly instantiate the direct (non-base-class, non-template) members:

[temp.explicit]#10 (emphasis mine)

An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes and members that are templates) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, provided that the associated constraints, if any, of that member are satisfied by the template arguments of the explicit instantiation ([temp.constr.decl], [temp.constr.constr]), except as described below. [ Note: In addition, it will typically be an explicit instantiation of certain implementation-dependent data about the class. — end note  ]

Note:
Expl. inst. declaration = extern template MyClass<Args>;, expl. inst. definition = template MyClass<Args>;

But, this is only done for members that are actually defined at the point of instantiation:

[temp.explicit]#11 (emphasis mine)

An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.

Since you did the explicit instantiation definition in the header (which is included by the source file), the definitions of the member functions come after your explicit instantiation of the class template, so those functions are not also explicitly instantiated.

It is therefore advisable to only perform (non-extern) explicit instantiation of a class template at the end of the source file that fully defines everything in it. The header file is certainly the wrong place.

Community
  • 1
  • 1
Max Langhof
  • 23,383
  • 5
  • 39
  • 72