C++ Visual studio不会使用*.inl实现编译模板类

C++ Visual studio不会使用*.inl实现编译模板类,c++,visual-studio,templates,visual-c++,compiler-errors,C++,Visual Studio,Templates,Visual C++,Compiler Errors,我正在阅读一本关于SFML游戏开发的书,但是我被困在了第二章,因为我无法编译我刚刚编写的代码 除了成员变量名和异常文本之外,它几乎是书中的逐字复制。我有C++和模板的经验,但是我以前从未见过这个错误,我已经盯着这个问题几个小时了,我没有发现这个代码有什么错误。 这是我的*.h文件: #pragma once #include <map> #include <memory> #include <string> #include <stdexcept>

我正在阅读一本关于SFML游戏开发的书,但是我被困在了第二章,因为我无法编译我刚刚编写的代码

除了成员变量名和异常文本之外,它几乎是书中的逐字复制。我有C++和模板的经验,但是我以前从未见过这个错误,我已经盯着这个问题几个小时了,我没有发现这个代码有什么错误。 这是我的*.h文件:

#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"
当我想使用该类时,我使用它如下:

ResourceHolder<sf::Texture, Textures::ID> textureHolder;
textureHolder.load(Textures::Airplane, "path/to/texture.png");

以上代码在msvc2012上编译。我刚刚删除了include enumFile.h,并添加了ResourceHolder的ctor和dctor。这是我的主要任务

更新

或者使用少量元编程:

/** Helper class to use integer in template parameters. */
template < Texture::ID >
struct EnumToStruct {
    static const Texture::ID value = e;
};

int main()
{
    Resource r;
    ResourceHolder< Resource, EnumToStruct<Texture::Car> > rh;
    rh.load( 30, "" );
}

从VS中的项目中删除或排除ResourceHolder.inl文件,然后再次添加它,为我解决了这个问题。我不知道为什么会这样,但现在它编译得很好

此问题是由inl文件的“文件类型”属性引起的。Visual Studio使用此属性确定在生成项目时如何处理文件。例如,“C++头文件”.h/hpp不会由头文件中的自身代码块编译,但“C/C++代码”.C/cpp文件除外

若您首先添加了一个C/CPP文件,并将其文件扩展名更改为inl,则在VC项目中,inl文件的“文件类型”必须保留为“C/C++代码”。但inl文件不是没有模板参数的可编译代码。所以它的文件类型不应该是“C/C++代码”。相反,将其设置为“C++头文件”或“文档”

将文件添加到VC++项目中时,VS会根据扩展名自动设置“文件类型”属性。和VS为inl文件设置“文档”文件类型。这就是为什么删除并重新添加inl文件解决了您的问题


请注意,编译模板代码实际上是在编译器处理某些使用它的代码(如头文件)时执行的。例如,如果在静态库项目中实现了一个模板类,而该模板类未在库项目中使用,则在构建该库项目时不会编译该类。相反,当您构建一个使用lib文件和带有模板参数的模板类的项目时,它将被编译。这就是为什么您应该在头文件中实现模板类的成员函数或模板化函数,或者在头文件中包含其他类似inl的内容。

我知道这是一个老话题,但我一直有同样的问题,直到几分钟前我还在读同一本SFML书,顺便说一句,我刚刚找到了一个快速而简单的解决方案,因此,我希望与大家分享,以供将来参考


在VisualStudio的“解决方案资源管理器”选项卡上,找到.inl文件并右键单击它。然后,选择“从项目中排除”选项。完成了

您编写的代码将使用msvc 2012进行编译。我刚刚删除了enumFile.h。所以问题是我怀疑模板void ResourceHolder::loadIdentifier id,const std::string&filename标识符必须是类或结构。这绝对有帮助!
ResourceHolder<sf::Texture, Textures::ID> textureHolder;
textureHolder.load(Textures::Airplane, "path/to/texture.png");
#include "resourceholder.h"

struct Resource
{
    bool loadFromFile( const std::string& filename )
    {
        return true;
    }
};

int main()
{
    Resource r;
    ResourceHolder< Resource, int > rh;
    rh.load( 30, "" );
}
namespace Texture { struct a_tag{ int id }; struct b_tag{ int id }; }
/** Helper class to use integer in template parameters. */
template < Texture::ID >
struct EnumToStruct {
    static const Texture::ID value = e;
};

int main()
{
    Resource r;
    ResourceHolder< Resource, EnumToStruct<Texture::Car> > rh;
    rh.load( 30, "" );
}