0

I'm trying to abstract away some GLFW input code by using a global variable state to keep track of key presses.

I thought using namespaces would be nice, so I thought doing something like:

namespace InputState
{
    namespace KeyPressed
    {
        static bool left = false;
        static bool right = false;
        static bool down = false;
        static bool up = false;
    };
};

and then accessing these variables like

if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
{
    InputState::KeyPressed::left = true;
}
else
{
    InputState::KeyPressed::left = false;
}

and

if (InputState::KeyPressed::left)
{
    body->velocity.x -= 0.25f;
}

would be really easy and visually/architecturally appealing, but as I've found out, creating static variables in namespaces brings some weird behavior that make this not work as intended.

I've tried using extern, but that gave me linker errors stating that there was a redefinition of the variables. I've triple checked that I have my header guards in place.

Is there some way I can get this working where I truly have a global variable within a namespace or is this just not possible/not intended behavior for namespaces?

Visual Studio
  • 184
  • 1
  • 10
  • You do it the same way as without namespaces. I suspect you made some mistake with `extern` (such as keeping the initialization of the variables in the header) that made you believe that namespaces are relevant to the issue. (Header guards only protect against multiple inclusions in a translation unit. If you include a definition in multiple translation units you still get multiple definitions.) – molbdnilo Nov 25 '21 at 10:34
  • 1
    In general, global variables are considered as bad. They rely on being changed in a function where this isn't obvious from its declaration that it does modify something with outside storage. Thus, such things become hard to understand and maintain as soon as the S/W grows. A replacement could be to put the resp. variables in a `struct` which is passed by reference (or `const` reference) where ever it's modified (or evaluated). A side effect would be that your `extern` issue would vanish. – Scheff's Cat Nov 25 '21 at 10:35
  • @Scheff'sCat I understand what you mean. This is in the context of a game engine and so I'm trying to figure out a way to maintain input state without just calling directly into the keyboard state that GLFW provides. The interface is quite ugly and my goal is to essentially abstract away everything GLFW related within my engine. Is there a better way without the use of structs as you mentioned? I feel like passing a struct around for keyboard state would become cumbersome and unwieldy quickly. – Visual Studio Nov 25 '21 at 10:49
  • 2
    _I feel like passing a struct around for keyboard state would become cumbersome and unwieldy quickly._ With a `struct` 1.) You don't need any global variable. A local variable in `main()` has sufficient life-time as well. 2.) The respective function to read out the keyboard state has to get a reference to that variable. 3.) Where you want to check the current keyboard state, you have to pass a const reference to that struct. – Scheff's Cat Nov 25 '21 at 10:53
  • 3
    -> Every where where functions handle the keyboard state, they will appear as argument in the function call. You might think that's tedious - I think that's easy to understand. (No surprises.) Btw. it's not only for other readers. I remember that I often enough didn't know anymore what I did in the code I wrote a half year ago (but this might be a matter of age). Finally, it's your code and you are free to do whatever you like most. (One of the advantages to write S/W I most appreciate.) It's just that I felt encouraged to give you another opinion... ;-) – Scheff's Cat Nov 25 '21 at 10:56

1 Answers1

2

Is there some way I can get this working where I truly have a global variable within a namespace or is this just not possible/not intended behavior for namespaces?

If you want to use these variables in other source file then you can do so using extern as follows:

myheader.h

#ifndef MYHEADER_H
#define MYHEADER_H
namespace InputState
{
    namespace KeyPressed
    {
        extern bool left, right, down, up;
    
    };
};

#endif

mysource.cpp

#include "myheader.h"
namespace InputState
{
namespace KeyPressed
    {
         bool left = false;
         bool right = false;
         bool down = false;
         bool up = false;
        }
 }

main.cpp

#include "myheader.h"
#include <iostream>

int main()
{
    std::cout<<InputState::KeyPressed::left<<std::endl;
    InputState::KeyPressed::left = true;
    std::cout<<InputState::KeyPressed::left<<std::endl;
}

Just like i have used the variable InputState::KeyPressed::left in main.cpp you can now use it in your own file and it will work.

The above program works as can be seen here.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • This works but it really is terrible code. – Konrad Rudolph Nov 25 '21 at 10:40
  • @KonradRudolph The question is about solving the issue that OP is facing.Nobody, literally nobody said that this is the best code ever or i have to write it in best way possible.It may happen that the OP is unaware of the fact global variables should not be used,in which case your comment might be useful to him.Again,i focus on solving the current problem.That is,i post the answer that answers(or at least tries to answer)what OP asked. **More importantly**,this answer can at least tell the OP about how to use the `extern` keyword in this scenario.Ofcourse the answer also solves his/her issue. – Jason Nov 25 '21 at 10:44
  • @KonradRudolph This is in the context of a game engine. I'm trying to create an interface to maintain input state. The idea was to have components that need input context to include the header, otherwise the input state remains untouched. The only time the values of the booleans get changed would be in a different header that directly listens for keyboard input via GLFW's keyboard input interface. What can I do that basically allows you to directly access grouped variables without the use of a class/instantiation? – Visual Studio Nov 25 '21 at 10:54
  • @AnoopRana There’s a place for answers that solve a narrow issue (hence no downvote from me) but it’s vastly more helpful to address the actual, underlying problem and fix *that*, or at least make OP aware of it. “Helping” people be more effective at writing bad code isn’t helping them at all, and is counter-productive in the long run. Instead, Stack Overflow should teach them write *better* code. – Konrad Rudolph Nov 25 '21 at 11:24
  • @RyanR I’m aware of the context, but it doesn’t justify using global variables. The comments under your question by “Scheff’s Cat” address this and provide the proper solution. – Konrad Rudolph Nov 25 '21 at 11:26
  • @KonradRudolph The question *does not* ask about *better alternatives to global variables*.Instead,the OP specifically said **Is there some way I can get this working where I truly have a global variable within a namespace or is this just not possible/not intnded behavior for namespaces?** and the OPseems to be well aware of the consequences of using global variable.He hasalready decided that he will be using global variables and is now asking forhelp to solve/do/achieve this properly.And my answer providesthis irrespective of the fact thatglobal variables should not be used in the first place – Jason Nov 25 '21 at 11:38
  • 1
    @AnoopRana “The question does not ask about better alternatives to global variables.” — My point is that *this is utterly irrelevant*. People often ask for bad solutions because they simply don’t know any better. As already mentioned, it is our task to teach them, not to help them write bad code. When answering questions on Stack Overflow, your task is to be a good teacher, not just an answering machine. — Also, you say that OP is “aware of the consequences”. Sure, but OP seems unaware that using this bad solution is unnecessary, and that better solutions exist. – Konrad Rudolph Nov 25 '21 at 11:41
  • @KonradRudolph IMO *it is our task to suggest them a better alternative(if any)* and not force(or get in their way) them when they are trying to learn to do a thing in a particular way. The use of `extern` keyword is still valid this(in this context) way. – Jason Nov 25 '21 at 11:51
  • @KonradRudolph The only problem that i have with your argument is that you said **The comments under your question by “Scheff’s Cat” address this and provide the proper solution**. Which is absolutely not correct in this case. Because the question asks a completely different thing and you're providing answer to a different question. – Jason Nov 25 '21 at 11:56
  • @AnoopRana OP has an [XY problem](https://en.wikipedia.org/wiki/XY_problem). Your answer shows how to do X, but the correct way would be to do Y via another (better) way. It is **extremely well established** that Stack Overflow does not condone answers which solve X for the OP without at least mentioning that X is a bad solution — hence why the comments by Scheff’s Cat are both correct and appropriate, and why your answer (despite being technically correct) isn’t a good answer. Please search the relevant meta discussions if you don’t believe me. – Konrad Rudolph Nov 25 '21 at 13:18