Gianni Mariani wrote in
Incomplete types are a convenient way to separate a hairy implementation
from the rest of the application. I've used this to separate a state
machine and an application. In the state machine implementation, a
state was allowed to be part of an expression. In the rest of the
application it was used as an indicator of the current state and the
only interesting operator was is equal. There were other incomplete
types e.g properties that were used to communicate values between app
and state machine. The expression system was big and potentially
misleading for the application and separating state machine and
application code forced application programmers to structure their code
better.
I overlooked the unary & operator implications. (Not that it was used
in the state machine) - just that it's the only operator that may me
used on an incomplete class - but may be overridden once the class is
defined.
It should be one of those big red flahing warnings when overloading
unary operator &.
Well It really applies to all operator's and overloadable function's
that take references or pointers.
But a template would/might not ... right ?
A template should use ADL (koenig lookup) at the point of instantiation
(as I understand it), so It should. My smart-ass remark about templates
being macro's was aluding to the fact many compilers will get this
right, even though they arn't doing the right thing.
[snip]
Note that the include order problem goes away if we 1) include
a complete declaration for X with member op &, or 2) provide a
declaration ( and optionaly a definition ) for a non-member op &.
I can think of few things in C++ where within a single scope, behaviour
of a function may change depending on where it is defined.
Overload resolution changes it all the time.
int f( double );
int example() { return f( 0 ); }
int f( int ); // move this up a line and the programme changes.
This is one more example whereby even though we use a template depending
on where it is first instantiated, it will either throw or not.
template <typename T>
inline bool Tequal( T & i, T & j )
{
return (&i) == (&j);
}
class X;
bool func( X & i, X & j )
{
return Tequal( i, j );
}
extern X a;
extern X b;
inline bool IsEqual( X & i, X & j )
{
return (&i) == (&j);
}
class X
{
public:
X * operator & () { throw "Yikes"; };
};
inline bool IsEqualOverride( X & i, X & j )
{
return (&i) == (&j);
}
[snip - main()]
I'm starting to think this is a language defect.
I changed main() thus:
#define Try( x ) { \
std::cout << #x "\t"; \
try {{x} std::cout << "OK"; } catch (char const *s) { std::cout << s; } \
std::cout << std::endl; }\
int main()
{
X x;
Try( func( x, x ); )
Try( Tequal( x, x ); )
Try( IsEqual( x, x ); )
Try( IsEqualOverride( x, x ); )
}
msvc 7.1 /Za:
func( x, x ); Yikes
Tequal( x, x ); Yikes
IsEqual( x, x ); OK
IsEqualOverride( x, x ); Yikes
gcc 3.2 (g++):
func( x, x ); OK
Tequal( x, x ); OK
IsEqual( x, x ); OK
IsEqualOverride( x, x ); Yikes
bcc32:
func( x, x ); OK
Tequal( x, x ); Yikes
IsEqual( x, x ); Yikes
IsEqualOverride( x, x ); Yikes
My reading would be that results should be OK, Yikes, OK, Yikes.
But this is impossible, as it means having 2 version's of Tequal<X>.
I think you're right about there being a defect in here. The question
is - what's the defect and what's the fix:
1) Have all overload resolution done by the linker - all output Yikes.
this hasn't got any legs, it just wouldn't be C++ anymore!
Breaks mode code than you can shake a stick at.
2) Stop ADL-at-point-of-instantiation adding to the overload set.
Output as gcc. But it breaks a whole bunch of existing template
code, some in namesace std!
3) Stop ADL-at-point-of-instantiation adding to the overload set if
and only if there is one or more (possibly compiler generated)
overloads available. Output as gcc again. Breaks less code than
(2), possibly some in namespace std.
I'd actually favour (2) as specialization does IMO a much cleaner
job than ADL-at-point-of-instantiation, particularly if we get
partial function specialization (*) as well.
(*) This is being considerd I belive.
Rob.