2013-07-26 36 views
2

我正在跟蹤一本關於SFML遊戲開發的書,但是我被困在第二章,因爲我無法編譯我剛剛編寫的代碼。Visual studio不會編譯帶* .inl實現的模板類

它幾乎是從書中逐字複製(成員變量名稱和異常文本除外)。我有使用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" 

,這裏是我的* .INL文件:

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; 
} 

對不起,大量的代碼,但我絕望這裏。我得到了不尋常的錯誤,所有在* .inl文件,而不是寫它們,我拍了一個截圖: VS2012 errors

任何想法如何解決這個問題?

編輯:一個關於如何使用類的字。

我和紋理命名空間中的枚舉(這就是「enumFile.h」是)

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

當我想使用這個類,我用它如下:

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

你寫的編譯與MSVC 2012年我剛delected「enumFile.h」的代碼。所以,問題是其他地方 –

+0

我已經在'模板中的一些犯罪嫌疑人 無效ResourceHolder <資源,標識符> ::負載(標識符ID,常量的std :: string和文件名)'標識符必須是一個類或一個結構。 –

回答

0

上面的代碼在msvc2012上編譯。我剛剛刪除了#include "enumFile.h,並添加了ResourceHolder的ctor和dctor。這是我的main

更新

#include "resourceholder.h" 

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

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

這裏的問題是,標識符不能是一個枚舉。標識符必須是結構體或類。您可以WIRTE東西

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, ""); 
} 
3

刪除或排除從VS項目的ResourceHolder.inl文件,然後將其再次解決了這個問題對我來說。我不知道爲什麼這個工作,但現在它編譯好。

+1

這絕對有幫助! –

1

此問題是由inl文件的「文件類型」屬性引起的。 Visual Studio使用此屬性來確定如何在構建項目時處理文件。例如,'C++頭文件'(.h/hpp)不會被自己編譯(頭文件中的代碼塊是例外的),但'C/C++代碼'(.c/cpp)文件不是。

如果您首先添加了C/CPP文件並將其文件擴展名更改爲inl,則inl文件的'文件類型'必須保留爲VC項目中的'C/C++代碼'。但是inl文件不是沒有模板參數的可編譯代碼。所以它的文件類型不應該是'C/C++代碼'。相反,將其設置爲「C++頭文件」或「文檔」。

當您將文件添加到VC++項目中時,VS會根據其擴展名自動設置「文件類型」屬性。VS爲inl文件設置'Document'文件類型。這就是刪除並重新添加inl文件解決您的問題的原因。

注意,編譯模板代碼實際執行時,編譯器處理某些代碼的使用它,就像一個頭文件。例如,如果你在一個靜態庫項目實現了一個模板類,它不是在您的庫項目中使用,該類不會當你構建的lib項目編譯。相反,當您使用lib文件和帶有模板參數的模板類來構建項目時,它將被編譯。這就是爲什麼你應該在頭文件中實現模板類或模板化函數的成員函數,或者像頭文件中包含的其他類似inl的其他東西。

1

我知道這是一個老話題,但我也有同樣的問題,直到幾分鐘前(我讀同一本書SFML,順便說一下),我只是發現了一個快速和簡單的解決方案,所以我想分享它以備將來參考。

在Visual Studio的「解決方案資源管理器」選項卡上,找到您的.inl文件和右鍵點擊它。然後,選擇選項「從項目中排除」。完成!

相關問題