Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Using map.emplace with sf::Shader  (Read 6804 times)

0 Members and 4 Guests are viewing this topic.

KRMisha

  • Newbie
  • *
  • Posts: 15
    • View Profile
Using map.emplace with sf::Shader
« on: May 03, 2017, 09:48:44 pm »
Hello,

I'm currently making a resource manager with which I can load, unload, or get a reference to a textures/fonts/soundbuffers/shaders. The problem is with the shaders: I can't seem to add them to an STL container (in my case, an std::unordered_map) because of the sf::NonCopyable. Even if I use .emplace(key, shader), my compiler doesn't accept it. How should I go about this?

Here is my current code:

const sf::Shader& ResourceManager::LoadShader(const std::string &rName, const std::string &rFilename, sf::Shader::Type type)
{
    // If a Shader is already loaded at the specified key, return the existing Shader
    std::unordered_map<std::string, sf::Shader>::const_iterator it = m_shaders.find(rName);
    if (it != m_shaders.cend())
    {
        return it->second;
    }
    // Otherwise, load the Shader
    sf::Shader shader;
    if (!shader.loadFromFile(rFilename, type))
    {
        std::cout << "ResourceManager error: Could not load Shader: \"" << rName << "\".\n";
        return m_shaders.at("ADDDEFAULTSHADER");
    }
    m_shaders.emplace(rName, shader); // Compiler error here because of deleted copy constructor
    return m_shaders.at(rName);
}
 

Thanks in advance!
« Last Edit: May 03, 2017, 10:54:51 pm by KRMisha »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Using map.emplace with sf::Shader
« Reply #1 on: May 03, 2017, 10:20:05 pm »
You are creating a shader and then passing it to the constructor of the new, emplaced shader, which would be the copy-constructor. Try emplacing it first and then loading it. If the load fails, you can always remove it.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

KRMisha

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Using map.emplace with sf::Shader
« Reply #2 on: May 03, 2017, 10:41:02 pm »
I tried this and it doesn't compile either.
/// Otherwise, load the Shader
    m_shaders.emplace(rName, sf::Shader());
    if (!m_shaders.at(rName).loadFromFile(ResourcePath() + rFilename, type))
    {
        std::cout << "ResourceManager error: Could not load Shader: \"" << rName << "\".\n";
        m_shaders.erase(rName);
        return m_shaders.at("ADDDEFAULTSHADER");
    }
    return m_shaders.at(rName);
 

To confirm that this isn't just a problem with my implementation in this case, I used an sf::Texture instead, which compiled successfully:
/// Otherwise, load the Shader
    m_textures.emplace(rName, sf::Texture());
    if (!m_shaders.at(rName).loadFromFile(ResourcePath() + rFilename, type))
    {
        std::cout << "ResourceManager error: Could not load Shader: \"" << rName << "\".\n";
        m_shaders.erase(rName);
        return m_shaders.at("ADDDEFAULTSHADER");
    }
    return m_shaders.at(rName);
 

Correct me if I'm wrong, but wouldn't the sf::Shader need a move constructor, which would let us do std::move to place it in an STL container? We could then use it like this (which currently doesn't work because of sf::NonCopyable):
/// Otherwise, load the Shader
    sf::Shader shader;
    if (!shader.loadFromFile(ResourcePath() + rFilename, type))
    {
        std::cout << "ResourceManager error: Could not load Shader: \"" << rName << "\".\n";
        return m_shaders.at("ADDDEFAULTSHADER");
    }
    m_shaders.emplace(rName, std::move(shader));
    return m_shaders.at(rName);
 
« Last Edit: May 03, 2017, 10:55:13 pm by KRMisha »

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: Using map.emplace with sf::Shader
« Reply #3 on: May 03, 2017, 10:49:05 pm »
You're still copying.

I think you want:
m_shaders.emplace(rName);

KRMisha

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Using map.emplace with sf::Shader
« Reply #4 on: May 03, 2017, 10:53:35 pm »
You're still copying.

I think you want:
m_shaders.emplace(rName);

That isn't valid syntax; it's an std::map/std::unordered_map

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Using map.emplace with sf::Shader
« Reply #5 on: May 03, 2017, 10:58:02 pm »
Doesn't just this:
m_shaders[rName];
create the shader in the map, ready to use?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

KRMisha

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Using map.emplace with sf::Shader
« Reply #6 on: May 03, 2017, 10:59:55 pm »
Doesn't just this:
m_shaders[rName];
create the shader in the map, ready to use?

Unfortunately not, it needs an assignment operator after it (=), which itself would need to call the copy constructor of the sf::Shader.

KRMisha

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Using map.emplace with sf::Shader
« Reply #7 on: May 03, 2017, 11:00:46 pm »
Doesn't just this:
m_shaders[rName];
create the shader in the map, ready to use?

Unfortunately not, it needs an assignment operator after it (=), which itself would need to call the copy constructor of the sf::Shader.

No, sorry, I'm wrong. It works! Thanks a lot :)

KRMisha

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Using map.emplace with sf::Shader
« Reply #8 on: May 03, 2017, 11:01:56 pm »
But shouldn't SFML allow support for std::move with sf::Shader? Or is this not possible?

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Using map.emplace with sf::Shader
« Reply #9 on: May 03, 2017, 11:04:25 pm »
Move constructors are C++11. SFML 2 is C++98.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: Using map.emplace with sf::Shader
« Reply #10 on: May 04, 2017, 01:02:01 pm »
You're still copying.

I think you want:
m_shaders.emplace(rName);

That isn't valid syntax; it's an std::map/std::unordered_map

Ah, you're right, I was thinking of C++17's try_emplace.