Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual studio won't compile template class with *.inl implementation

I'm following a book about SFML game development, but I'm stuck on the second chapter, because I can't compile the code I just wrote.

It's almost word-by-word copy from the book (except from member variable name and exception text). I have experience with C++ and templates, but I have never seen this error before and I've been staring at this for few hours now and I don't see anything wrong with this code.

Here is my *.h file:

#pragma once
#include <map>
#include <memory>
#include <string>
#include <stdexcept>
#include <cassert>
#include "enumFile.h"

template <typename Resource, typename Identifier>
class ResourceHolder
{
public:
    ResourceHolder(void);
    ~ResourceHolder(void);

    void load(Identifier id, const std::string & filename);

    template <typename Parameter>
    void load(Identifier id, const std::string & filename, 
              const Parameter& secondParam);

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

private:
    std::map<Identifier, std::unique_ptr<Resource>> resourceMap;
};

#include "ResourceHolder.inl"

and here is my *.inl file:

template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& filename)
{
    // Create and load resource
    std::unique_ptr<Resource> resource(new Resource());
    if (!resource->loadFromFile(filename))
        throw std::runtime_error("Failed to load resource: " + filename);

    // If loading successful, insert resource to map
    auto inserted = resourceMap.insert(std::make_pair(id, std::move(resource)));
    assert(inserted.second);
}

template <typename Resource, typename Identifier>
template <typename Parameter>
void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& filename, 
                                                const Parameter& secondParam)
{
    // Create and load resource
    std::unique_ptr<Resource> resource(new Resource());
    if (!resource->loadFromFile(filename, secondParam))
        throw std::runtime_error("Failed to load resource: " + filename);

    // If loading successful, insert resource to map
    auto inserted = resourceMap.insert(std::make_pair(id, std::move(resource)));
    assert(inserted.second);
}

template <typename Resource, typename Identifier>
Resource& ResourceHolder<Resource, Identifier>::get(Identifier id)
{
    auto found = resourceMap.find(id);
    assert(found != resourceMap.end());

    return *found->second;
}

template <typename Resource, typename Identifier>
const Resource& ResourceHolder<Resource, Identifier>::get(Identifier id) const
{
    auto found = resourceMap.find(id);
    assert(found != resourceMap.end());

    return *found->second;
}

Sorry for a lot of code, but I'm desperate here. I'm getting unusual errors, all in the *.inl file, instead of writing them, I took a screenshot: VS2012 errors

Any idea how to fix this?

EDIT: a word on how the class is used.

I have and enum inside a texture namespace (that is what "enumFile.h" is)

namespace Textures
{
    enum ID {Landscape, Airplane, Missile};
}

When I want to use the class, I use it as follows:

ResourceHolder<sf::Texture, Textures::ID> textureHolder;
textureHolder.load(Textures::Airplane, "path/to/texture.png");
like image 593
isklenar Avatar asked Nov 18 '25 18:11

isklenar


2 Answers

Removing or excluding the ResourceHolder.inl file from the project in VS and then adding it again solved the problem for me. I have no idea as to why this worked, but now it compiles fine.

like image 76
h0wser Avatar answered Nov 21 '25 08:11

h0wser


This problem is caused by 'File Type' property of your inl file. Visual Studio use this property to determine how to handle a file while building a project. For example, 'C++ Header File'(.h/hpp) will not be compiled by itself(code block in header file is exceptional), but 'C/C++ Code'(.c/cpp) files are does.

If you added a C/CPP file at first and changed its file extension to inl, 'File Type' of inl file must be remaining as 'C/C++ Code' in VC project. But inl file is not a compilable code without template arguments. So it's file type should not be 'C/C++ Code'. Instead, set it to 'C++ Header File' or 'Document'.

When you add files into VC++ project, VS automatically set 'File Type' property according to their extension. And VS sets 'Document' file type for inl files. This is why removing and re-adding that inl file solved your problem.

Note that compiling templated code is actually performed when compiler process some codes that use it, like a header file. For example, if you implemented a template class in a static library project and it's not used in your library project, that class will not be compiled when you build that lib project. Instead, when you build a project that use lib file and the template class with template arguments, it will be compiled. This is why you should implement member functions of template class or templated functions in header file or something else like inl which is included in header file.

like image 23
Codeption Avatar answered Nov 21 '25 08:11

Codeption



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!