[英]C++ SFML Gamedev Book - Unresolved External Symbol from ResourceHolder class
我有以下三個文件,其中找不到我所產生的錯誤的來源:
Main.cpp
#include <SFML/Graphics.hpp>
#include <iostream>
#include "ResourceHolder.h"
namespace Textures
{
enum ID { Landscape, Airplane, Missile };
}
int main()
{
//...
try
{
ResourceHolder<sf::Texture, Textures::ID> textures;
textures.load(Textures::Airplane, "Airplane.png");
}
catch (std::runtime_error& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
//...
}
ResourceHolder.h
#pragma once
#include <map>
#include <string>
#include <memory>
#include <stdexcept>
#include <cassert>
template <typename Resource, typename Identifier>
class ResourceHolder
{
public:
void load(Identifier id, const std::string& fileName);
Resource& get(Identifier id);
const Resource& get(Identifier id) const;
private:
void insertResource(Identifier id, std::unique_ptr<Resource> resource);
std::map<Identifier, std::unique_ptr<Resource>> mResourceMap;
};
ResourceHolder.cpp
#include "ResourceHolder.h"
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("ResourceHolder::load - Failed to load " + fileName);
}
//If loading was successful, insert resource to map
insertResource(id, std::move(resource));
}
template <typename Resource, typename Identifier>
Resource& ResourceHolder<Resource, Identifier>::get(Identifier id)
{
auto found = mResourcemap.find(id);
assert(found != mResourceMap.end());
return *found->second();
}
template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::insertResource(Identifier id, std::unique_ptr<Resource> resource)
{
//Insert and check success
auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource)));
assert(inserted.second);
}
如果要在main.cpp中刪除try-catch組合,則代碼可以正常編譯; 但是,如果我將其保留在此處,則會出現LNK2019(未解析的外部符號)錯誤。
此錯誤的根源是什么,我該如何解決?
您無法在.cpp文件中定義模板。 必須在標頭中定義它們,以便編譯器可以看到實現並生成特定的類。
這是為什么的一個更好的問題/答案,為什么模板只能在頭文件中實現? 。
編輯: get
函數中有什么問題
兩件事情。
首先是auto found = mResourcemap.find(id);
。 您的地圖名稱不正確, m
應該為大寫-> mResourceMap
。
然后該行return *found->second();
。 映射迭代器包含一對,並且第一個和第二個成員不是函數,而是數據成員。 您應該寫return *found->second;
。
我建議您在使用模板之前先了解要使用的結構。 模板的編譯錯誤非常凌亂且難以閱讀。 另外,您可以制作一個單獨的測試程序,並制作一個沒有模板的資源管理器,以更輕松地理解您的錯誤,然后在工作的資源管理器之上構建模板。
在所有其他答案為您提供了足夠的信息后,您的代碼為什么無法編譯並且可能無效,這是我前一段時間為SFML編寫的資源管理器,可能對您有用:
HPP文件:
#ifndef RESOURCEMANAGER_HPP
#define RESOURCEMANAGER_HPP
/************ INCLUDES ***********/
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <memory>
#include "SFML/Graphics.hpp"
#include "SFML/Audio.hpp"
class ResourceManager
{
private:
std::map<std::string,std::unique_ptr<sf::Texture>> listImageContainer;
std::map<std::string,std::pair<std::unique_ptr<sf::SoundBuffer>,std::unique_ptr<sf::Sound>>> listSoundContainer;
std::map<std::string,std::unique_ptr<sf::Font>> listFontContainer;
public:
ResourceManager();
std::unique_ptr<sf::Sound>& LoadSound(const std::string);
std::unique_ptr<sf::Font>& LoadFont(const std::string);
std::unique_ptr<sf::Texture>& LoadImage(const std::string);
~ResourceManager();
};
#endif
CPP文件:
#include "ResourceManager.hpp"
ResourceManager::ResourceManager()
{
}
std::unique_ptr<sf::Sound>& ResourceManager::LoadSound(const std::string _fileName)
{
if (listSoundContainer.find(_fileName) == listSoundContainer.end())
{
std::unique_ptr<sf::SoundBuffer> soundBuffer(new sf::SoundBuffer());
if (soundBuffer->loadFromFile("assets/sound/" + _fileName) != false)
{
std::unique_ptr<sf::Sound> sound(new sf::Sound(*soundBuffer));
listSoundContainer[_fileName] = std::make_pair(std::move(soundBuffer), std::move(sound));
return listSoundContainer[_fileName].second;
}
else
{
std::cerr << "Error loading sound..." << std::endl;
}
}
else
{
return listSoundContainer[_fileName].second;
}
}
std::unique_ptr<sf::Font>& ResourceManager::LoadFont(const std::string _fileName)
{
if (listFontContainer.find(_fileName) == listFontContainer.end())
{
std::unique_ptr<sf::Font> font(new sf::Font());
if (font->loadFromFile("assets/font/" + _fileName)!=false)
{
listFontContainer[_fileName] = std::move(font);
return listFontContainer[_fileName];
}
else
{
std::cerr << "Error loading font..." << std::endl;
}
}
else
{
return listFontContainer[_fileName];
}
}
std::unique_ptr<sf::Texture>& ResourceManager::LoadImage(const std::string _fileName)
{
if (listImageContainer.find(_fileName) == listImageContainer.end())
{
std::unique_ptr<sf::Texture> texture(new sf::Texture);
if (texture->loadFromFile("assets/image/" + _fileName)!=false)
{
listImageContainer[_fileName] = std::move(texture);
return listImageContainer[_fileName];
}
else
{
std::cerr << "Error loading image: " << _fileName << std::endl;
}
}
else
{
return listImageContainer[_fileName];
}
}
ResourceManager::~ResourceManager(){}
如何使用:
ResourceManager resourceManager;
auto& sound = resourceManager.LoadSound("nice.wav");
auto& image = resourceManager.LoadImage("head.png");
auto& sound2 = resourceManager.LoadSound("nice.wav"); //<--- already loaded
sound.play();
etc...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.