Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Seven Round Things
Mar 22, 2010
I hate macros and try to avoid them if at all possible, but I'm torn here. I made a Signal class:
code:
handy::arch::Signal<void(int x, int y)> onMoved;
I didn't make it simply
code:
handy::arch::Signal<int, int> onMoved;
because 1) I might want to add return types/combiners in the future and 2) this way I can name the parameters inline in a declaration, making my code more self documenting, I.E.:
code:
Signal<void(IDrawable& sprite, int x, int y)> onSpriteMoved;
It gets rather cluttered having the useless void( and ) everywhere, so I made a macro:
code:
#define HANDY_SIGNAL(...) handy::arch::Signal<void(__VA_ARGS__)>

// More readable
HANDY_SIGNAL(IDrawable& sprite, int x, int y) onSpriteMoved;
Basically I think this one macro is harmless but I want to know if there are any ways it could bite me.

Adbot
ADBOT LOVES YOU

That Turkey Story
Mar 30, 2003

Seven Round Things posted:

I hate macros and try to avoid them if at all possible, but I'm torn here. I made a Signal class:
code:
handy::arch::Signal<void(int x, int y)> onMoved;
I didn't make it simply
code:
handy::arch::Signal<int, int> onMoved;
because 1) I might want to add return types/combiners in the future and 2) this way I can name the parameters inline in a declaration, making my code more self documenting, I.E.:
code:
Signal<void(IDrawable& sprite, int x, int y)> onSpriteMoved;
It gets rather cluttered having the useless void( and ) everywhere, so I made a macro:
code:
#define HANDY_SIGNAL(...) handy::arch::Signal<void(__VA_ARGS__)>

// More readable
HANDY_SIGNAL(IDrawable& sprite, int x, int y) onSpriteMoved;
Basically I think this one macro is harmless but I want to know if there are any ways it could bite me.

Is writing void really that bad? Using your macro name is no fewer characters. I'd personally just get used to it.

If you really want a macro, the only potential concern I can think of is that you should be fully qualifying in the macro (in other words, start the type with :: in the off-chance that someone is invoking the macro from a namespace that has its own "handy").

Really though, you should just use a template alias for this instead of a macro, assuming your compiler supports them:

code:
template< class... Params >
using Signal_ = Signal< void( Params... ) >;

Deffon
Mar 28, 2010

^^
edit: fb.

In c++11 you can declare your handy signal like this:

code:
template<typename... Args>
using HANDY_SIGNAL = handy::arch::Signal<void(Args...)>;
And use it like this:
code:
HANDY_SIGNAL<IDrawable&, int, int> onSpriteMoved;
Don't think you could give names to the template parameters though.

Other than that, your macro solution can theoretically cause namespace scoping problems, but its probably not going to happen.

Seven Round Things
Mar 22, 2010

quote:

template alias
Don't think you could give names to the template parameters though.
Exactly, I don't want to give that up because I'm making an engine-type thing with lots of signals and it makes it much more readable:
code:
Signal<void(int64_t deltaMS)>          onTick;
Signal<void()>                         onQuit;

Signal<void(int x, int y)>             onMouseMoved;
Signal<void(int button)>               onMouseClicked;
Signal<void(int x, int y, int button)> onMouseDown;

That Turkey Story posted:

Is writing void really that bad? Using your macro name is no fewer characters. I'd personally just get used to it.
I suppose it's not. To be honest, the main reason I'm hesitant is because someone else seeing HANDY_SIGNAL won't immediately know that it is just a wrapper for declaring a Signal- they'll think it's a trigger for a bunch of difficult-to-understand preprocessor wizardry.

I think I'll just use the void() syntax after all, it does also make it clearer that the functions to be attached to it must return void... thanks!

Rottbott
Jul 27, 2006
DMC

Seven Round Things posted:

I suppose it's not. To be honest, the main reason I'm hesitant is because someone else seeing HANDY_SIGNAL won't immediately know that it is just a wrapper for declaring a Signal- they'll think it's a trigger for a bunch of difficult-to-understand preprocessor wizardry.
I would indeed expect something like that, and in general code is much easier to read when you know you are in fact reading the actual code. Even if it is a bit long-winded.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
I'm curious now - I haven't seen a construct of that form before (the Signal<void(int x,int y)> thing). How would you use something like this, and for what? I see they're being used to referencing onClick behaviors or something, is the idea to have your input-triggered functions able to be in a list of some sort on an object? What would a simple usage of the class look like?

Posting Principle
Dec 10, 2011

by Ralp

roomforthetuna posted:

I'm curious now - I haven't seen a construct of that form before (the Signal<void(int x,int y)> thing). How would you use something like this, and for what? I see they're being used to referencing onClick behaviors or something, is the idea to have your input-triggered functions able to be in a list of some sort on an object? What would a simple usage of the class look like?

Take a look at std::function for a similar example of that syntax.

Seven Round Things
Mar 22, 2010

roomforthetuna posted:

How would you use something like this, and for what? I see they're being used to referencing onClick behaviors or something, is the idea to have your input-triggered functions able to be in a list of some sort on an object? What would a simple usage of the class look like?
It's a signal/slot system, of which there are many others. I declare a signal:
code:
Signal<void(int x, int y)> onMoved;
And connect any number of functions to it:
code:
void doSomethingWhenMoved(int x, int y)
{
	// do something
}

onMoved.connect(&doSomethingWhenMoved);
onMoved.connect(&doSomethingElseWhenMoved);
onMoved.connect([](int x, int y){ /* Use lambdas too */});
Then when the move happens, I can call
code:
onMoved.emit(42, 69);
once, and all the functions who connected will be called.

I can disconnect a function when I no longer want it to receive events by saving the ID and passing it to disconnect():
code:
auto id = onMoved.connect(&doSomethingWhenMoved);
// ...
onMoved.disconnect(id);
There is a RAII wrapper for this:
code:
{
  auto scoped = onMoved.connectScoped(&doSomethingWhenMoved);
  // ...
}
// scoped's destructor disconnects the connections
If I connect a member function like this:
code:
onMoved.connectTracked(&MyClass::doSomething, someInstanceOfMyClass);
and MyClass derives from handy::arch::IHasTrackedConns, all such connections will be disconnected automatically when someInstanceOfMyClass is destroyed (freeing you from having to disconnect everything in the destructor manually).

In a GUI system, for example, you might connect many functions to a Button's onClicked. In a game engine, you might have onMouseClicked, onMouseMoved, onKeyReleased, onJoystickButtonPressed, etc.

Again this isn't a new idea, there are many such systems including boost::signals2 and nano-signal-slot. I'm quite happy with mine, though, and making it was educational.

Seven Round Things fucked around with this message at 21:31 on Jul 13, 2013

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Seven Round Things posted:

[use of his signal]
Thanks, that was exactly what I was looking for (even with the lambda example in there which I was thinking about but hadn't asked)!

And thanks Jerry SanDisky too, for the link explaining the syntax of declaring such a thing. Looks like I should bone up on my C++11 a bit!

bobua
Mar 23, 2003
I'd trade it all for just a little more.

I'm trying to create a simple Camera object...

code:
struct Camera{
	DWORD CameraID;
	CHAR Camera_SN[MAX_SIZE];
	HANDLE handle;
};
Later, when I use it...

code:
HANDLE handle1 = //code here to return handle

Camera cam1 = {0, 0, handle1};
I get an intelisense error on handle1: a value of type "HANDLE" cannot be used to initialize an entity of type "CHAR".

I've never worked with handles before. Is a handle actually a CHAR or something?

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender
No. Your "code here to return handle" is wrong, most likely. Try posting your actual code so we have a chance to identify the problem.

bobua
Mar 23, 2003
I'd trade it all for just a little more.

I haven't put it in yet, but am using it elsewhere. It's part of an api for the camera... it's just

code:
HANDLE handle = NULL;
OpenDevice(0, &handle);

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

bobua posted:

code:
Camera cam1 = {0, 0, handle1};
You're trying to initialize a char array with just 0. My guess is the next entry, handle1, is trying to fill in the second character of that char array.

Maybe try initializing the char array with "" rather than 0.

bobua
Mar 23, 2003
I'd trade it all for just a little more.

roomforthetuna posted:

You're trying to initialize a char array with just 0. My guess is the next entry, handle1, is trying to fill in the second character of that char array.

Maybe try initializing the char array with "" rather than 0.

This appears to be the right track, I commented out the device id and sn and it stopped complaining about the handle. Thanks.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
The struct definition, in the eyes of the first initializer, is equivalent to:

C++ code:
struct Camera{
	DWORD CameraID;
	CHAR Camera_SN0;
	CHAR Camera_SN1;
	CHAR Camera_SN2;
	CHAR Camera_SN3;
	CHAR Camera_SN4;
        /* ... */
	CHAR Camera_SN_MAX_SIZE;
	HANDLE handle;
};
Thus, your initializer is putting the HANDLE in the part of the struct meant for a CHAR, and the compiler is complaining. The other form of initializer, the one with the "", is smart enough to recognize that this should be a C string.

Posting Principle
Dec 10, 2011

by Ralp
I'm going to be moving from a mainly C++ job to something else, but would like to keep up with C++. What's the landscape look like for open source C++ projects that need contributors?

Computer viking
May 30, 2011
Now with less breakage.

Jerry SanDisky posted:

I'm going to be moving from a mainly C++ job to something else, but would like to keep up with C++. What's the landscape look like for open source C++ projects that need contributors?

There's always KDE, though the way they use Qt and kdelib might make it too much of a niche if you want to keep up with c++ in general.

covener
Jan 10, 2004

You know, for kids!

Jerry SanDisky posted:

I'm going to be moving from a mainly C++ job to something else, but would like to keep up with C++. What's the landscape look like for open source C++ projects that need contributors?

FWIW Apache Traffic Server (proxy server) is c++

MrMoo
Sep 14, 2000

GCC, LLVM, Clang, LLDB, Chromium, Boost should be pretty obvious large C++ projects.

Some of the NoSQL projects should be in C++. Some of the messaging fabrics are: QPID, 0mq.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
DO NOT VOLUNTARILY WORK WITH THE GCC CODEBASE

Posting Principle
Dec 10, 2011

by Ralp
We used to have a fork of stdlibc++ and that scared me off GNU code forever. Mozilla and Boost look most promising.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

Otto Skorzeny posted:

DO NOT VOLUNTARILY WORK WITH THE GCC CODEBASE

A coworker, David Malcolm, used to be a core Python developer, and he got switched over to the gcc/tools team. His first project was to turn gcc into a better library, so he wrote a simple analysis pass that detected wherever code used global state, and recompiled gcc with it.

The log file was 12MB.

Here's his plan for removing global state from GCC.

I wish him the best of luck at not going insane.

shrughes
Oct 11, 2008

(call/cc call/cc)
That is epic and awesome. I also wish the best of luck and skill to him.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
His singleton optimization is extremely clever, and he's planning on making it an optimization that's externally usable by other projects as well.

He's a smart engineer.

Pontificating Ass
Aug 2, 2002

What Doth Life?
I got back to coding lately and was looking for a way to write 'global classes' without resorting to something like a singleton. I ended up abusing the static keyword to make classes that look like this (some kind of mouse wrapper):

code:
class Mouse
{
public:
	static void SetMousePos(Vector2f newPos);
	static Vector2f GetPos();
private:
	static Vector2f pos;
};

#include "Mouse.h"

void Mouse::SetMousePos(Vector2f newPos)
	{ _pos=newPos; }

Vector2f Mouse::GetPos()
	{ return _pos; }

sf::Vector2f Mouse::_pos;
This is the simplest example I could find, which let's me do something like easily get the Mouse's position from just about anywhere with Mouse::GetPos(). The ugliest part is defining the private variables at the end of the .cpp, but it overall makes me feel a lot better than using the singleton syntax.

It works but since this is C++ I know there's a problem with the approach. Is my use of global functionality abusive? Is this creating a bunch of copies of _pos? Is there a better way to access single-instance classes?

Pontificating Ass fucked around with this message at 00:44 on Jul 20, 2013

Slurps Mad Rips
Jan 25, 2009

Bwaltow!

Sintax posted:

It works but since this is C++ I know there's a problem with the approach. Is my use of global functionality abusive? Is this creating a bunch of copies of _pos? Is there a better way to access single-instance classes?

The static local function variable :eng101:

code:
class Mouse {
  Mouse();
public:
  static Mouse& ref() {
    static Mouse instance;
    return instance;
  }
};

Posting Principle
Dec 10, 2011

by Ralp

SAHChandler posted:

The static local function variable :eng101:

code:
class Mouse {
  Mouse();
public:
  static Mouse& ref() {
    static Mouse instance;
    return instance;
  }
};

Just a heads up, this is not thread safe unless you have a compiler that properly implements the C++11 memory model.

seiken
Feb 7, 2005

hah ha ha

Sintax posted:

I got back to coding lately and was looking for a way to write 'global classes' without resorting to something like a singleton. I ended up abusing the static keyword to make classes that look like this (some kind of mouse wrapper):

code:
class Mouse
{
public:
	static void SetMousePos(Vector2f newPos);
	static Vector2f GetPos();
private:
	static Vector2f pos;
};

#include "Mouse.h"

void Mouse::SetMousePos(Vector2f newPos)
	{ _pos=newPos; }

Vector2f Mouse::GetPos()
	{ return _pos; }

sf::Vector2f Mouse::_pos;
This is the simplest example I could find, which let's me do something like easily get the Mouse's position from just about anywhere with Mouse::GetPos(). The ugliest part is defining the private variables at the end of the .cpp, but it overall makes me feel a lot better than using the singleton syntax.

It works but since this is C++ I know there's a problem with the approach. Is my use of global functionality abusive? Is this creating a bunch of copies of _pos? Is there a better way to access single-instance classes?

I mean it's not necessarily wrong but you're really just recreating namespace functionality in a different way. The mouse position in this particular example is essentially a global variable and you should regard it as such. (For something like a mouse position that is likely totally fine, just don't make the mistake thinking putting things in static accessor functions magically makes them not global variables)

seiken fucked around with this message at 12:59 on Jul 20, 2013

nielsm
Jun 1, 2009



seiken posted:

I mean it's not necessarily wrong but you're really just recreating namespace functionality in a different way. The mouse position in this particular example is essentially a global variable and you should regard it as such. (For something like a mouse position that is likely totally fine, just don't make the mistake thinking putting things in static accessor functions magically makes them not global variables)

And then sometimes there is more than one mouse. And sometimes you don't have one at all. (Like tablets with touch.)
I'm sure it's fine for the purpose of showing variations over the singleton pattern, but in reality you may need to treat "the mouse position" differently.
For instance, you may want to store historical mouse states in some way and pass those around, "2 seconds ago the mouse was at that position and the left button was held down" and such.

Rottbott
Jul 27, 2006
DMC

nielsm posted:

And then sometimes there is more than one mouse. And sometimes you don't have one at all. (Like tablets with touch.)
I'm sure it's fine for the purpose of showing variations over the singleton pattern, but in reality you may need to treat "the mouse position" differently.
For instance, you may want to store historical mouse states in some way and pass those around, "2 seconds ago the mouse was at that position and the left button was held down" and such.
I've seen it so many times. E.g. someone in the past assumed 'only ever one mouse', and then I had to port the code to the Wii where there are 0-4 pointers!

I detest singletons and avoid them like the plague. I end up passing a lot of parameters around. Even things which seem like they are physically 'singletons' such as hardware resources often turn out not to be later.

pseudorandom name
May 6, 2007

Jerry SanDisky posted:

Just a heads up, this is not thread safe unless you have a compiler that properly implements the C++11 memory model.

GCC has had thread safe static local construction since before C++11.

Posting Principle
Dec 10, 2011

by Ralp

pseudorandom name posted:

GCC has had thread safe static local construction since before C++11.

Kind of. It used a global shared mutex for local static initializations, meaning it was still easy to deadlock. They've fixed this now, but it was broken and non portable for a long time.

Dog Jones
Nov 4, 2005

by FactsAreUseless
Microsoft's C++ compiler just confused the poo poo out of me. I was debugging a really simple programming, and getting frustrated because the code was so simple, and it wasn't behaving properly.

The root of the problem was, the values of one of my variables just wasn't changing as I was stepping through in the debugger:

code:
// i is instead equal to 7 at this point, and somehow, exists before this 
// declaration
int i = 0;
// still 7
i++;
// still 7
i = 3;
Given that 'i' already had a value before the declaration, I was really confused that re-declaring it didn't throw an error. I looked back up through the program, and saw that I used 'i' in a for loop like so:

code:
for(int i = 0; i < aVariable; ++i)
	// do stuff
I thought this meant that 'i' only existed in the scope of the for loop, and was pretty disappointed that my compiler was telling me that I didn't know the first thing about what I was doing. So I went to msdn and saw this:
http://msdn.microsoft.com/en-us/library/vstudio/b80153d8.aspx

MSDN posted:

The C++ standard says that a variable declared in a for loop shall go out of scope after the for loop ends...

By default, under /Ze, a variable declared in a for loop remains in scope until the for loop's enclosing scope ends.

/Zc:forScope enables standard behavior of variables declared in for loops without needing to specify /Za.

So why does microsoft's c++ compiler not comply to the standard by default? Even assuming they had a good reason to do this, why am I allowed to redeclare 'i' in a scope where its already declared without my compiler giving me an error? And on top of all that, why does that suddenly make the increment and assignment operators take no effect? All of this with no indication of the compiler, jeez.

Dog Jones fucked around with this message at 21:08 on Jul 20, 2013

Rottbott
Jul 27, 2006
DMC
/Zc:forScope is the default...

Dog Jones
Nov 4, 2005

by FactsAreUseless

Rottbott posted:

/Zc:forScope is the default...

Alright, now I'm really confused. I used all default settings (like I said, this is a small project). I looked at my options and in fact /Zc:forScope is specified. So now I have no idea why the program is behaving like this.

edit: To be precise, here is the behavior.

code:
for(int i = 0; i <= 7; ++i)
	; // i's value goes from 0 to 7 as you would expect
// no error or warning, and i still equals 7
int i = 0;
// these lines don't change i's value, it remains 7.
i += 3;
i--;

Dog Jones fucked around with this message at 23:47 on Jul 20, 2013

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
Visual c++ is older than the standard and its legacy behavior is that loop init declarations survive the loop. Depending on what you have edited out of your example, you might be seeing the effects of unused value elimination.

nielsm
Jun 1, 2009



It looks more likely to me that it's just the debugger that's confused by the name collision, but you probably really do have two separate variables. If this is a debug (non-optimised) build, the compiled probably allocates separate slots on the stack for each "i" but the debugger doesn't follow scope properly and keeps inspecting the location for the loop-counter even when it's actually out of scope.
Have you tried adding regular code to somehow output the variables, that doesn't rely on debugger inspection?

Xerophyte
Mar 17, 2008

This space intentionally left blank

Dog Jones posted:

Alright, now I'm really confused. I used all default settings (like I said, this is a small project). I looked at my options and in fact /Zc:forScope is specified. So now I have no idea why the program is behaving like this.

I tried reproducing this. I get the wrong values (i == 7) in the VC2012 debugger, which presumably is looking at the wrong part of the stack, but the program behaves as expected when run and the scoping rules are enforced by MSVC.

C++ code:
int main() {
  for(int i = 0; i < 7; ++i) {
    printf( "%i\n", i ); // 0 .. 6 
  }
  // printf( "%i\n", i ); // will not compile
  int i = 0;
  printf( "%i\n", i ); // 0
  i += 3;
  printf( "%i\n", i ); // 3
  i--;
  printf( "%i\n", i ); // 2
  system("pause");
}

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Xerophyte posted:

I tried reproducing this. I get the wrong values (i == 7) in the VC2012 debugger, which presumably is looking at the wrong part of the stack, but the program behaves as expected when run and the scoping rules are enforced by MSVC.
I'm curious whether the debugger would get it right if the outer-scope declaration of i was made before the for loop, like so.

C++ code:
int main() {
  int i=0;
  for(int i = 0; i < 7; ++i) {
    printf( "%i\n", i ); // 0 .. 6 
  }
  printf( "%i\n", i ); // 0
  i += 3;
  printf( "%i\n", i ); // 3
  i--;
  printf( "%i\n", i ); // 2
  system("pause");
}

roomforthetuna fucked around with this message at 00:57 on Jul 21, 2013

Adbot
ADBOT LOVES YOU

Dog Jones
Nov 4, 2005

by FactsAreUseless
I tried a test similiar to Xerophyte, and got the same results, so nielsm is probably right.

roomforthetuna posted:

I'm curious whether the debugger would get it right if the outer-scope declaration of i was made before the for loop, like so.

C++ code:
int main() {
  int i=0;
  for(int i = 0; i < 7; ++i) {
    printf( "%i\n", i ); // 0 .. 6 
  }
  printf( "%i\n", i ); // 0
  i += 3;
  printf( "%i\n", i ); // 3
  i--;
  printf( "%i\n", i ); // 2
  system("pause");
}

The debugger still gets it wrong with this program.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply