On 08/26/2013 01:10 PM, Francisco Jerez wrote:
Ian Romanick <i...@freedesktop.org> writes:
[...]
Disadvantage (b) can be made painless with the macro I discuss below.
IMHO it would be nicer to define generic templates implementing
overloads for all bitwise operators. They would have to reference the
bitmask_enumeration_traits structure so they would be discarded for
non-bitmask types.
[...]
Second, we could arrange for the expression 'FOO op BAR' (with 'FOO' and
'BAR' enumerants from different incompatible bitmask types) to be
rejected by the compiler by means of a static assertion in the
definition of 'T op S'. If we use the macro solution below the compiler
will accept that expression by downgrading both T and S to integers and
then applying the built-in definition of 'op'. Though it would still
refuse to assign the result to a variable of any of both types *if* the
user is doing that.
As a non-C++ programmer, that explanation gave me a headache. I don't
think this project is ready yet for its developers to need that level
of knowledge of the C++ type system.
I can immediately understand Chad's macro, and I can also (nearly
immediately) understand that it's probably not the "C++ way."
My explanation is exactly as relevant if we stick to Chad's solution or
not, using macros doesn't save you from getting the unexpected effect I
was trying to describe -- quite the opposite, I can't think of any
simple way to work around that problem without using templates.
The thing is that defining bitwise operators separately for each enum
type, as this patch and the macro solution do, doesn't stop the compiler
From using the corresponding built-in integer operators when it doesn't
find a match among the user-defined ones. That means that if we have
two bitfield enumerants from two different disjoint types
e.g. "SEASON_OF_THE_YEAR_SUMMER" and a "CPU_ARCHITECTURE_I386", the
compiler is still going to accept expressions like
"SEASON_OF_THE_YEAR_SUMMER | CPU_ARCHITECTURE_I386", which might not be
what had been expected if the BRW_CXX_ENUM_OPS macro was used in an
attempt to improve the code's type safety.
This sounds insane.
If there are no operator overloads, the compiler rejects:
enum foo f(enum foo a, enum foo b)
{
return a | b;
}
Then we add operloads:
enum foo operator|(enum foo, enum foo);
enum bar operator|(enum bar, enum bar);
And now the compiler will accept:
unsigned f(enum foo a, enum bar b)
{
return a | b;
}
That can't be right. Am I missing something? Or am I reinforcing my
point about not being ready for this level of C++ ninjitsu...
The template-based solution might seem somewhat obscure to the
inexperienced C++ programmer, but unlike the macro-based one it would be
semantically sound, and this is just one of many reasons why it's a good
idea for anyone dealing with C++ code to have at least some basic
knowledge on using templates -- it's the cleanest way to do static
polymorphism and generic programming in C++.
That said, I agree that it would be a bad idea to make a sudden
transition to template metaprogramming in components of our tree where
the majority of maintainers have a strong preference towards old-school
C programming, but that's no reason to reject a small, non-intrusive and
potentially useful change in the good direction a priori before having
seen any of the code...
[...]
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev