1

I've been reading the book SFML Game Development, and I wanted to create a template class. I've separated it in 2 files: a .h file and a .inl file like so:

// ResourceHolder.h
#ifndef _RES_HOLDER
#define _RES_HOLDER
#include <map>
#include <memory>
#include <SFML/Graphics.hpp>

namespace Resources
{
    enum ID {LandscapeTexture, AirplaneTexture, MissileTexture};

    template<typename Resource> 
    class ResourceHolder
    {   
    public:
        void load(Resources::ID id, const std::string& file);
        template<typename Parameter>
        void load(Resources::ID id, const std::string&file,
            const Parameter& param);

        Resource& get(Resources::ID id);
        const Resource& get(Resources::ID id) const;

    private:
        std::map<Resources::ID, std::unique_ptr<Resource>> mResourceMap;

    };
#include "ResourceHolder.inl"
};
#endif

.

//ResourceHolder.inl
template<typename Resource>
void Resources::ResourceHolder<Resource>::load(Resources::ID id,
                                  const std::string& file) 
{
    std::unique_ptr<Resource> resource(new Resource());
    if(!resource->loadFromFile(file))
        throw std::runtime_error("ResourceHolder::load failed to load : "+file);
    mResourceMap.insert(std::make_pair(id, std::move(resource)));
}

template<typename Resource>
template<typename Parameter>
void Resources::ResourceHolder<Resource>::load(Resources::ID id,
                                     const std::string& file,
                                     const Parameter& param) 
{
    std::unique_ptr<Resource> resource(new Resource());
    if(!resource->loadFromFile(file, param))
        throw std::runtime_error("ResourceHolder::load failed to load : "+file);
    mResourceMap.insert(std::make_pair(id, std::move(resource)));
}

template<typename Resource>
Resource& Resources::ResourceHolder<Resource>::get(Resources::ID id) 
{
    auto found = mResourceMap.find(id);
    return *found->second;
}

template<typename Resource>
const Resource& Resources::ResourceHolder<Resource>::get(Resources::ID id) const 
{
    auto found = mResourceMap.find(id);
    return *found->second;
}

But when I try to compile it, I get these errors:

1>  ResourceHolder.inl
1>d:\workspaces\resourceholder.inl(2): error C2143: syntax error : missing ';' before '<'
1>d:\workspaces\resourceholder.inl(2): error C2182: 'ResourceHolder' : illegal use of type 'void'
1>d:\workspaces\resourceholder.inl(2): error C2988: unrecognizable template declaration/definition
1>d:\workspaces\resourceholder.inl(2): error C2059: syntax error : '<'
1>d:\workspaces\resourceholder.inl(2): error C2039: 'load' : is not a member of '`global namespace''
1>d:\workspaces\resourceholder.inl(2): error C2653: 'Resources' : is not a class or namespace name
1>d:\workspaces\resourceholder.inl(3): error C2039: 'string' : is not a member of 'std'
1>d:\workspaces\resourceholder.inl(13): error C2039: 'load' : is not a member of '`global namespace''
1>d:\workspaces\resourceholder.inl(13): error C2653: 'Resources' : is not a class or namespace name
1>d:\workspaces\resourceholder.inl(14): error C2039: 'string' : is not a member of 'std'
1>d:\workspaces\resourceholder.inl(16): error C2143: syntax error : missing ';' before '{'
1>d:\workspaces\resourceholder.inl(16): error C2447: '{' : missing function header (old-style formal list?)
1>d:\workspaces\resourceholder.inl(24): error C2143: syntax error : missing ';' before '<'
1>d:\workspaces\resourceholder.inl(24): error C2040: 'ResourceHolder' : 'Resource &' differs in levels of indirection from 'int'
1>d:\workspaces\resourceholder.inl(24): error C2530: 'ResourceHolder' : references must be initialized
1>d:\workspaces\resourceholder.inl(24): error C2988: unrecognizable template declaration/definition
1>d:\workspaces\resourceholder.inl(24): error C2059: syntax error : '<'
1>d:\workspaces\resourceholder.inl(24): error C2039: 'get' : is not a member of '`global namespace''
1>d:\workspaces\resourceholder.inl(24): error C2653: 'Resources' : is not a class or namespace name
1>d:\workspaces\resourceholder.inl(31): error C2039: 'get' : is not a member of '`global namespace''
1>d:\workspaces\resourceholder.inl(31): error C2653: 'Resources' : is not a class or namespace name
1>d:\workspaces\resourceholder.inl(32): error C2143: syntax error : missing ';' before '{'
1>d:\workspaces\resourceholder.inl(32): error C2447: '{' : missing function header (old-style formal list?)

I've tried to figure it out for the past 2 hours, also I've tried eliminating the namespace.

What is the proper way of making a template class separated in a .h file and a .inl file?

EDIT:

This seems to be the proper way. The errors are there because VS studio saw my .inl file as a source file and tried to compile it. To get rid of that problem I removed it from my project and then added it again.

Romeo
  • 521
  • 5
  • 20
  • 1
    possible duplicate of [Splitting templated C++ classes into .hpp/.cpp files--is it possible?](http://stackoverflow.com/questions/1724036/splitting-templated-c-classes-into-hpp-cpp-files-is-it-possible) – Jon Nov 25 '13 at 13:30
  • The accepted answer to that question is a good explanation – dutt Nov 25 '13 at 13:33
  • So it's not possible of putting the implementation in a .inl file? – Romeo Nov 25 '13 at 13:34
  • Are you compiling with C++11 features? You may have to separate `>>` with a space `> >` here: `std::map>`. Also, you are including the `.inl` file inside the namespace. But in this file you assume you are outside (`Resources::`). – Guilherme Bernal Nov 25 '13 at 13:37
  • @Jon, I don't see this as a duplicate. He is not trying to compile it as two files. He just organized as two files and included one into the other. The issue here is unrelated. – Guilherme Bernal Nov 25 '13 at 13:42
  • I've tried including the file outside the namespace. Same problem. Also i've tried the space betweed `>>`. Nothing changes. – Romeo Nov 25 '13 at 13:42
  • @GuilhermeBernal: If one is included into the other then it's just one file for practical purposes. You could be right, but that's not how I read the question. – Jon Nov 25 '13 at 13:43
  • I use 2 files for keeping the code clean. I know it is not possible to separate them in .h and .cpp as with normal classes. – Romeo Nov 25 '13 at 13:46
  • I could compile the code just fine with gcc 4.8.1. You are probably using some feature not supported by your version of msvc. – Guilherme Bernal Nov 25 '13 at 13:48
  • But i sure don't understand why's that because I have VS 2012 ultimate. – Romeo Nov 25 '13 at 13:51
  • 1
    I've found the problem. If anybody else is having this problem is because Visual Studio thinks that your .inl file is a source file and tries to compile it. To solve this you need to remove it from project and add it again. If in your project browser is displayed with an icon with 2 "+" besides it, it won't compile. That is the icon for source files. – Romeo Nov 25 '13 at 13:58
  • 1
    You may make an answer from it and accept. – Guilherme Bernal Nov 25 '13 at 14:00
  • I can do that in about 8 hours or so. Till then i edited the question so anyone can see. Thank you Guilherme. – Romeo Nov 25 '13 at 14:03
  • Perfectly legal to have files that don't compile in your project. VS can ignore them if you "exclude them from build". Do this by setting properties on the affected file (from the solution explorer) – egur Nov 25 '13 at 18:03

1 Answers1

0

I've found the answer. If anybody else is having this problem is because Visual Studio thinks that your .inl file is a source file and tries to compile it.

To solve this, you need to remove it from your project and add it again. If in your project browser is displayed with an icon with 2 "+" besides it, it won't compile. That is the icon for source files.

Romeo
  • 521
  • 5
  • 20