any way to do this without the ugly macro?

Started by
26 comments, last by l0calh05t 17 years ago
Quote:Original post by l0calh05t
Actually, I didn't argue it was good design, only that it is better design than using a typedef
Oh, ok. Sorry, I wasn't certain of what you were implying.

Quote:And I still have to get used again to actually having non-member functions at my disposal.
Once you're more accustomed to the standard library, I'm sure you'll come to appreciate them [wink].
MumbleFuzz
Advertisement
Quote:Original post by MumbleFuzz
Oh, ok. Sorry, I wasn't certain of what you were implying.


No need to apologize, no harm done. And I like a good discussion ;-)

Quote:Once you're more accustomed to the standard library, I'm sure you'll come to appreciate them [wink].


Or rather as soon as I am more accustomed with it *again*, after 2, almost 3, years of not writing anything in C++ you do forget a few things.

(And about the "oh the horror" after scheme for any scheme proponents that should hang around here - if any: In the first semester we were forced to implement "objects" in scheme and i remember many a last line of code which looked approximately like this: ))))))))))))))))))
Quote:
That won't work for the exact reason why I needed the macro.


What?
You won't need the macro at all. The compiler will give you the default copy/assign which are are quite enough. In fact implementing them at all (using the macro in this case) is really bad idea i suspect*
class vecy : public tuple<int,2>{public         // Don't need this         // CSE_TUPLE_ASSIGN_MACRO(vecy,int,2)	 // dont need this either         // vecy() {}};

*
Your class would not be a aggregate if you implemnt any of the ctors and that would prevent you from doing nice array-like initializations like so
tuple<int,4> quad = { 2, 3, 4, 5 }; // error

I for one would really like that syntax for these small array-types.
Remove these lines from your tuple class and that array init will work.
tuple() {} and protected:
tuple<int,4> quad = { 2, 3, 4, 5 }; // fine

Yah, inheriting from boost.array would make it a non-aggregate aswell however it already was so i wansnt doing any more damage :)
you can however make boost.array a member var and just delegate to it. However that doesnt save you much work at all.
But for the love of god add standard iterator support to your tuple class.
Quote:Original post by Amnesty2
What?
You won't need the macro at all. The compiler will give you the default copy/assign which are are quite enough. In fact implementing them at all (using the macro in this case) is really bad idea i suspect*
class vecy : public tuple<int,2>{public         // Don't need this         // CSE_TUPLE_ASSIGN_MACRO(vecy,int,2)	 // dont need this either         // vecy() {}};


That will not work. You are forgetting about the operators.

Quote:*
Your class would not be a aggregate if you implemnt any of the ctors and that would prevent you from doing nice array-like initializations like so
tuple<int,4> quad = { 2, 3, 4, 5 }; // error

I for one would really like that syntax for these small array-types.
Remove these lines from your tuple class and that array init will work.
tuple() {} and protected:
tuple<int,4> quad = { 2, 3, 4, 5 }; // fine


That overloading the "braces constructor" isn't possible in C++ (yet?) is not my fault.

Quote:Yah, inheriting from boost.array would make it a non-aggregate aswell however it already was so i wansnt doing any more damage :)
you can however make boost.array a member var and just delegate to it. However that doesnt save you much work at all.
But for the love of god add standard iterator support to your tuple class.


Honestly... why? Sorry, but pretty much all stl algorithms make no sense on this tuple (except perhaps for-each, but implementing the iterators just for that seems like a waste of time)
Quote:
That will not work. You are forgetting about the operators.

What? Can you explain because you might need to redefine some operators in your dervied classes but you DON'T need to define copy/assignment operators for your tuple class. And unless you add some complex data types in your dervied classes you wont need copy/assignment operators their either.
Quote:
That overloading the "braces constructor" isn't possible in C++ (yet?) is not my fault.

You don't need 'overload' it.
Simply remove
tuple() {}
and the protected keyword in your tuple class and it will work.
tuple<char,3> abc = { 'a', 'b', 'c' } // this is now fine, and works as expected

It is up to you really if you want to make your tuple class an aggregate-type.
Personally, initializing like this is very worthwhile in this case. IMO
Quote:
Honestly... why? Sorry, but pretty much all stl algorithms make no sense on this tuple (except perhaps for-each, but implementing the iterators just for that seems like a waste of time)

'on this tuple'
Of course they make sence. Its a generic finite array. Yes, they don't make much sence on specific instances like color/vec4 which you intend to use it for right out of the box. However, once this class is all polished up nice and neat you will find it useful in lots of other places where the context would make a lot of sence for the algorithms.

Just trying to help you out here.
Quote:Original post by Amnesty2
What? Can you explain because you might need to redefine some operators in your dervied classes but you DON'T need to define copy/assignment operators for your tuple class. And unless you add some complex data types in your dervied classes you wont need copy/assignment operators their either.


I would have to redefine *all* operators because of the return types. And only having to define them once was the whole point of the tuple class.

Quote:You don't need 'overload' it.


But if it were possible one could provide that kind of syntax, even if the object is *not* an aggregate (which does limit your possibilities)

Quote:Simply remove
tuple() {}
and the protected keyword in your tuple class and it will work.
tuple<char,3> abc = { 'a', 'b', 'c' } // this is now fine, and works as expected

It is up to you really if you want to make your tuple class an aggregate-type.
Personally, initializing like this is very worthwhile in this case. IMO

'on this tuple'
Of course they make sence. Its a generic finite array. Yes, they don't make much sence on specific instances like color/vec4 which you intend to use it for right out of the box. However, once this class is all polished up nice and neat you will find it useful in lots of other places where the context would make a lot of sence for the algorithms.

Just trying to help you out here.


It's only supposed to be used for such "specific instances" if I need generic finite arrays there is boost::array (and many others), and if it were supposed to be that i would have called it so.
Quote:Original post by l0calh05t
Thats what i did (last post):


So you did :).

Quote:2) boost::tuple


I meant boost::array here, not that this bears any extra special relevance :P

Quote:Thats one of the things I don't like about the C++ template syntax. When I specialize a template, I have to reimplement *all* functions, even if I just want to change a few.


C++ template syntax is easier to talk about in terms of the few things it gets right that the huge list of things it gets wrong ;-).

Quote:
Quote:If you don't trust it to:

Sorry about that forgot a :-P I was just kidding about the "not trusting" part, at least with what concerns inlining.


Ahh, I see, quite alright.

Quote:
Quote:I'm pointing out everywhere "Self" was used in my example (except as a return type), I could've used "arith_array_base" without any problems, since:

1) "each arith_array_base will be a different type", yes
2) None of this code depends on things defined only in the superclass (RE: my first sentance)


except for the problems it would cause with the copy assign operator, right?


Actually, as I noted earlier, copy assignment cannot use Self in the first place as an argument type, and must explicitly cast to it if that's required:

Quote:9) Although it was not involved here, copy-construction and assignment are special cases in that the arguments involved cannot simply be Self, as they will not override the autogenerated versions. Instead, if the members of Self were required, you would end up with something like:

arith_array_base( const arith_array_base & other_ ) {    const Self& other = static_cast< const Self& >( other_ );    ...}




Quote:Original post by l0calh05t
And what if I want to normalize a vector? Or if I want to multiply it with a matrix? Sure I could have non-member functions for those, but that's kinda circumventing the whole object-oriented design thing.


Nah, a function being a non-member doesn't make it somehow less OO. Just a little less convenient to implement. That and it doesn't play well with polymorphism under C++.

Quote:Original post by Amnesty2
Quote:
That will not work. You are forgetting about the operators.

What?


See the return types of operator*,*=,+,+=, etc, which should be of the most derived class type, but without the macro or CRTP will instead be the base class type, disallowing operations such as: (a + b).normal(), where a and b are of type vector and yet (a+b) would be of type arith_array_base instead.

Quote:Can you explain because you might need to redefine some operators in your dervied classes


Yes, he would (as outlined above), which would be stupid given that they would do the exact same thing, which is the whole point of solving that with either:

1) A macro
2) Something else (CRTP)
Quote:Original post by MaulingMonkey
-snip-

C++ template syntax is easier to talk about in terms of the few things it gets right that the huge list of things it gets wrong ;-).


Still is one of my favorite language features.

Quote:
-snip-
Quote:
Quote:I'm pointing out everywhere "Self" was used in my example (except as a return type), I could've used "arith_array_base" without any problems, since:

1) "each arith_array_base will be a different type", yes
2) None of this code depends on things defined only in the superclass (RE: my first sentance)


except for the problems it would cause with the copy assign operator, right?


Actually, as I noted earlier, copy assignment cannot use Self in the first place as an argument type, and must explicitly cast to it if that's required:

Quote:9) Although it was not involved here, copy-construction and assignment are special cases in that the arguments involved cannot simply be Self, as they will not override the autogenerated versions. Instead, if the members of Self were required, you would end up with something like:

arith_array_base( const arith_array_base & other_ ) {    const Self& other = static_cast< const Self& >( other_ );    ...}


I must have overlooked the "(except as a return type)" part

Quote:
Quote:Original post by l0calh05t
And what if I want to normalize a vector? Or if I want to multiply it with a matrix? Sure I could have non-member functions for those, but that's kinda circumventing the whole object-oriented design thing.


Nah, a function being a non-member doesn't make it somehow less OO. Just a little less convenient to implement. That and it doesn't play well with polymorphism under C++.

-snip-


And it won't automatically land on the same page as the object in doxygen docs (if i am not mistaken)

This topic is closed to new replies.

Advertisement