SFML community forums

Help => General => Topic started by: ka0s420 on February 20, 2016, 08:33:17 am

Title: SFML book, chapter 2 issue
Post by: ka0s420 on February 20, 2016, 08:33:17 am
Hello, I am currently working through the SFML Game Development book. I am on chapter 2 at the part where we first declare the namespace called Textures. I have declared the namespace, created the enum in my main.cpp, and when I start to make a header file for the TextureHolder class, the book says to add this map declaration:

private:
 std::map<Textures::ID,
 std::unique_ptr<sf::Texture>> mTextureMap;

The code doesn't work for me, I get error '::' must be followed by a namespace or class name. I do not know how to access the namespace from the main.cpp in this header. The book doesn't show how, and neither does the github code, partially, I think because the github code is what it could/should look like at the end of the chapter. I have seen that it is possible to declare a namespace in a header file and include that into TextureHolder.h, but in the book it is declared in main.

Any advice on how to achieve this step in the book would be appreciated.
Title: Re: SFML book, chapter 2 issue
Post by: ramaskrik on February 20, 2016, 09:09:32 am
Are you sure you include the sf::Texture header in that file?

Something like
#include <SFML/Graphics/Texture.hpp>
or
#include <SFML/Graphics.hpp>
Title: Re: SFML book, chapter 2 issue
Post by: ka0s420 on February 20, 2016, 09:19:13 am
hey, yeah I have included <SFML/Graphics.hpp>, but that's not what my issue is. My issue is that in the book/tutorial they make a namespace Textures, an enum for storing ids to later refer to textures. Its the part Textures::ID that causes the error that stops the program from compiling. And I'm not sure how I'm supposed to access the namespace from within that header file, having only declared the namespace in the main.cpp.

here is my code:
TextureHolder (where the error is):
#pragma once
#include <map>
#include <string>
#include <memory>
#include <stdexcept>
#include <cassert>
#include <SFML/Graphics.hpp>

class TextureHolder
{
        private:
                std::map <Textures::ID, std::unique_ptr<sf::Texture>> mTextureMap;
};

Main.cpp (where the namespace and enum are created):
#include <SFML/Graphics.hpp>
#include "Game.h"

namespace Textures
{
        enum ID
        {
                starfield,
                ship,
                laser
        };
}

int main()
{
        Game game;
        game.run();

        return 0;
}

Other than that there is the game class - header and cpp - but I don't believe they hold any relevance to this.
Title: Re: SFML book, chapter 2 issue
Post by: ramaskrik on February 20, 2016, 09:24:10 am
Textures::ID doesn't exist in the TextureHolder.h

Move your Textures::ID enum to the TextureHolder.h (or, even better, movie it to a new file and include the file where appropriate)
Title: Re: SFML book, chapter 2 issue
Post by: Nexus on February 20, 2016, 11:53:55 am
Do it as it is done in the later chapters: move the enum with its namespace to a separate file (https://github.com/SFML/SFML-Game-Development-Book/blob/master/10_Network/Include/Book/ResourceIdentifiers.hpp).

By the way, wrapping enums in a namespace is a C++98 idiom that we used for compatibility with early C++11 compilers. If your compiler supports type-safe enums (enum class/enum struct), consider using it instead.
Title: Re: SFML book, chapter 2 issue
Post by: ka0s420 on February 20, 2016, 09:35:55 pm
okay so i got it to work last night, by declaring the namespace and the enum in the textureHolder class header and including that header in my game class and then storing the textureHolder as a member variable in the game class.

however this is a bit messy and not very modular so I will do as Nexus suggested and put it in it's own file. As for using the c++11 strongly typed enum, from what I can gather, I would literally just use, for example, enum class textureId, and not use the namespace, because the strongly typed nature of enum class means that the enums are safely locked behind texturedId::textureName, which was the whole point of using a namespace. Is this correct?

code for clarity:
use:
enum class textureId
{
    textureName1,
    textureName2,
    etc..
};
instead of:
namespace Textures
{
    enum ID
    {
        textureName1,
        etc...
    };
}
 
Title: Re: SFML book, chapter 2 issue
Post by: Ausche on February 21, 2016, 02:59:08 am
however this is a bit messy and not very modular so I will do as Nexus suggested and put it in it's own file. As for using the c++11 strongly typed enum, from what I can gather, I would literally just use, for example, enum class textureId, and not use the namespace, because the strongly typed nature of enum class means that the enums are safely locked behind texturedId::textureName, which was the whole point of using a namespace. Is this correct?

I believe that's what he was saying.
You can check out more on these Strongly Typed Enums here:  http://www.cprogramming.com/c++11/c++11-nullptr-strongly-typed-enum-class.html (http://www.cprogramming.com/c++11/c++11-nullptr-strongly-typed-enum-class.html)
Title: Re: SFML book, chapter 2 issue
Post by: ka0s420 on February 22, 2016, 01:14:18 am
Hi, yeah thanks, I had actually seen that article prior to my last question. Just needed some reassurance based on my presumptions. Although it seems to do the same thing, sadly, when you use enum class but no namespace, you lose the convention of each enum being ID:: so it's not as uniform, but still. I'll do it. 
Title: Re: SFML book, chapter 2 issue
Post by: Nexus on February 22, 2016, 11:01:55 am
Although it seems to do the same thing, sadly, when you use enum class but no namespace, you lose the convention of each enum being ID:: so it's not as uniform, but still.
What do you mean? With strongly typed enums, the enumerator must be prefixed with the enum name.
Title: Re: SFML book, chapter 2 issue
Post by: ka0s420 on February 22, 2016, 11:49:01 am
I mean that without adding a unique namespace for each enum class you don't get the uniformity of having all the enums called ID. I realise it is still very similar, plus is shorter to write, I just simply liked that each enum was prefixed with ID, no biggie.
Title: Re: SFML book, chapter 2 issue
Post by: SeriousITGuy on February 22, 2016, 11:49:42 am
Be careful when using enum classes in the context of the SFML Game Development book. The book uses the unsigned int representation of enum's to make bitwise operations on them. This does not work by default with enum class values. To make it work you either need to overload the bitwise operators for your enum classes, or, the simpler solution, casting the enum class values to unsigned int before doing bitwise operations.
I use the second solution but with a generic casting function, which casts an enum class value to its underlying type (for which you should define the underlying type for your enum classes like enum class Textures : unsigned int { ... };, which also means you are able to forward declare an enum class, which comes in handy when working with the context structure later in the book. )
here is the code for said function:
template<typename T>
constexpr auto to_integral( T t ) -> typename std::underlying_type<T>::type
{
  return static_cast<typename std::underlying_type<T>::type>( t );
}
Title: Re: SFML book, chapter 2 issue
Post by: Nexus on February 22, 2016, 01:55:16 pm
A very nice idiom is to overload the unary + operator in a way that converts to the underlying type. This way, the enumerators can be used in bitwise operations or as indices without an overly verbose syntax 8)
Title: Re: SFML book, chapter 2 issue
Post by: SeriousITGuy on February 22, 2016, 03:37:40 pm
I once read in a good book about C++ (More Effective C++ by Scott Meyers), that it is tempting to overload binary operators like '+', '-' etc. for non-arithmetic types, but most often it isn't a good idea because of its overly non-verbose syntax and your actual operation get's lost behind the simple and implicit + syntax. So because of that, I will never ever overload operator '+' and instead write a generic converter function with an explicit name to state what I am doing with the supplied type.
(One can still argue if an enum class of unsigned int is a non-arithmetic type, I do, with the exception of std::string)