According to the standart applying sizeof to void is not allowed and
will result in a compiler error. (correct me if I'm wrong).
Now I'd like to describe a scenario in which it would be helpfull to
have
sizeof(void) with a defined value (zero would sound reasonable for me).
Given a Container of heterogenous Objects, which supports serialization,
deserialization and value-copy for any Type T which allows:
T t; // def.ctor
const T t1 (t); // copy-ctor
t=t1; // op=
flattenImpl (some_ostream, t1);
inflateImpl (some_istream, t);
Now I want my container to support a new, human readable serialization
format (namely xml). The Idea is to use a function:
xmlWriteImpl (some_ostream, t1) // xmlReadImpl(..,..) ommited
This function should be used in "xml"-serialization if it is aviable,
otherwise, the flattenImpl function should be used.
One way to achieve this would be to require the Client to write a
template-specialization of xmlWriteImpl for any class with a special xml
ser.-output, and a default implementation which calls flattenImpl.
But now there is somethink like this:
void xmlWriteImpl(ostream& os, const Serialzable& s)
{
s.serializeXML(os);
}
This function should be called for ANY subclass of serializable. We
don't want to write a specialization for any subclass. (That doesn't
mean that all our Container-Elements are subclasses of Serializable, but
some are).
So the idea is to detect if there is any suitable xmlWriteImpl function
and call it if existent, otherwise call flattenImpl.
To do so, we define a function which will qualify as the worst match:
class RemarkablyHuge {char _[79111];};
RemarkablyHuge xmlWriteImpl(ostream& os, ...);
Now we can be pretty sure that if the best match for xmlWriteImpl
returns a value as huge as RemarkablyHuge, there is no user defined
version of it:
template <class T> void xmlWrite(ostream& os, const T& t)
{
if (sizeof(RemarkablyHuge) == sizeof(xmlWriteImpl(os,t )))
flattenImpl(os, t);
else
xmlWriteImpl(os, t);
}
And here lies the problem. Normally a user defined xmlWriteImpl function
will return void. And sizeof void may not be taken. So the whole hack
just doesn't work.
The questions are:
1) Is there any work-around for this problem ?
2) What do you think about requiring xmlWriteImpl to return ostream& ?
3) Why is sizeof(void) not allowed in the first place?
Any help appreciated.
Best Regards,
Tim
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
Because of 2) a new rule, which does not exist, would sound reasonable to
me:
5) sizeof may not be applied to any incomplete type, expect void
Robert Kindred
"Tim Walkenhorst" <tim.wal...@gmx.de> wrote in message
news:004601c2076d$36d8c200$7e5b...@mshome.net...
<snip>
> template <class T> void xmlWrite(ostream& os, const T& t)
> {
> if (sizeof(RemarkablyHuge) == sizeof(xmlWriteImpl(os,t )))
> flattenImpl(os, t);
> else
> xmlWriteImpl(os, t);
> }
<snip>
Because void is not a type. It is the absence of the type. So what is
the size of nothing? So how bright is a black hole?...
Attila
Well we certainly could do that, but I am far from convinced that the
very limited utility is worth the special casing.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Anyway, there is always a way around.
For instance, in you specific case, you could take advantage of the fact
that the signatures of the possible 'xmlWriteImpl' if pretty bounded and use
the following metaprogram to disptach accordingly to the return type of that
functions.
I'll show the technique with this example program:
#include<iostream>
typedef char no ;
typedef char yes [2] ;
template<class T> struct returns_void { typedef no type ; } ;
template<> struct returns_void<void> { typedef yes type ; } ;
template<class R>
returns_void<R>::type does_it_returns_void ( R (*) () ) ;
template< std::size_t >
void do_something()
{
std::cout << "doing something for a function which doesn't return void\n"
;
}
template<>
void do_something< sizeof(yes) >()
{
std::cout << "doing something for a function which does return void\n" ;
}
void foo() ;
int bar() ;
double fred() ;
int main()
{
do_something< sizeof ( does_it_returns_void(foo) ) > () ;
do_something< sizeof ( does_it_returns_void(bar) ) > () ;
do_something< sizeof ( does_it_returns_void(bar) ) > () ;
}
You can add as many 'does_it_return_void' overloads as needed to accomodate
all the possible signatures you need to handle.
HTH,
--
Fernando Cacciola
Sierra s.r.l.
fcac...@gosierra.com
www.gosierra.com
You may view it that way, and pragmatically that makes perfectly good
sense but according to the Standards (C & C++) it is a type and
participates in the type system. Unfortunately there is a second use of
void where it is not a type:
void foo(void);
The two uses of void are technically entirely different. The keyword is
most unfortunately overloaded.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Well, that certainly is interesting. But, unfortunatly, it doesn't seem to
help in my case. In order to call the does_it_return_void function you've to
know the address of the function you want to inspect. But unfortunatly I
don't have it. xmlWriteImpl is a heavily overloaded function, and I need the
compiler to find me the right version, WITHOUT calling it. The only way I
can image to do this is by applying sizeof.
Thanks anyway
Tim
"sizeof may be applied to any function-call, expect to those which return
void."
>From this perspective you would not add a special case, but remove a special
case.
In a previous article you mentioned:
> Actually if void was a complete type dereferencing a void* would be
> meaningful which we do not want.
This was as an argument for the decision that void is defined as an
incomplete type. But you may dereference(*) any pointer to an incomplete
type, expect void:
class Incomplete;
void process (Incomplete&);
void deref (Incomplete* i) {process(*i);}
I would conclude that void is already in more cases different from the other
incomplete types than not. void does not seem to be an incomplete type at
all. It is something special, which requires special rules(**).
Best Regards
Tim
(*) Is dereferencing not a misleading term? Actually you might be tempted to
think that to dereference means to obtain a value from a reference to a
value. But it doesn't. It means to obtain a reference to a value from a
pointer to a value.
(**) From the standpoint of language design (ignoring compatibility issues
and metaprogramming issues), I would remove void altogether:
void foo(); would be replaced by procedure
foo();
It would no longer be allowed to ignore function results. In my opinion a
function should either return something meaningful, which may not be
ignored, or nothing at all.
void* would be replaced by pointer
int foo(void) would be disallowed
>
>I would conclude that void is already in more cases different from the other
>incomplete types than not. void does not seem to be an incomplete type at
>all. It is something special, which requires special rules(**).
Indeed. I have always thought the concept of void was something of a
hack shoe-horned into the C grammar. However there are quite a few
places where we hack to get round the fact that C & C++ lack procedures.
(IMO ctors and dtors are procedures as well)
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
template <typename T>
struct MySizeOf {
static const size_t value = sizeof(T);
};
template <>
struct MySizeOf <void> {
static const size_t value = 0;
};
Now, in your code, whenever you need the sizeof a type, just do this:
MySizeOf<type>::value
and you get the size of the type, at compile time, with "void" yielding you "0".
joshua lehrer
factset research systems
template <typename T>
struct MySizeOf {
static const size_t value = sizeof(T);
};
template <>
struct MySizeOf <void> {
static const size_t value = 0;
};
Now, in your code, whenever you need the sizeof a type, just do this:
MySizeOf<type>::value
and you get the size of the type, at compile time, with "void" yielding you "0".
joshua lehrer
factset research systems
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
The Function I want to implement is: (PSEUDOCODE)
template <class T>
void xmlWrite(ostream& os, const T& t)
{
if ( __COMPILES__("xmlWriteImpl(os, t)") ) // if there is an
appropriate version of xmlWriteImpl
__EXECUTE__("xmlWriteImpl(os, t)") // ->call it
else
flattenImpl(os, t); // Default-Implemtation, will always work
}
Since I am unable to write somethink like __COMPILES__ I have to make
the call to xmlWriteImpl always work.
This is quite simple:
class VerySpecial {char _ [777777];}
VerySpecial xmlWriteImpl(...); // will be the worst match for any call
to xmlWriteImpl
given this, and a typeof operator (none-standart), I could implement
xmlWrite like this:
template <class T>
void xmlWrite(ostream& os, const T& t)
{
if (! typeEqual<typeof(xmlWriteImpl(os, t)), VerySpecial>::result)
xmlWriteImpl(os, t);
else
flattenImpl(os, t);
}
But there is no typeof operator in c++, so the only tool I can use is
sizeof. And sizeof will fail if xmlWriteImpl returns void.
I hope this made my problem a bit clearer.
Tim
int foo() ;
sizeof(foo()) ; // ok: same as sizeof(int)
MySizeOf< foo() > ; // error: function call expressions cannot be template
parameters.
Tim is trying to 'partially' match an overloaded function, which is only
possible with a function call (a complete match is possible with an
appropriate function pointer, but this requires the complete signature).
Tim's problem is essensially the following:
Given a set of overloaded functions, such as:
void foo(int);
void foo(double);
void foo(char);
How do I know whether there exist an overload for an arbitrary type T ?
This is a very good problem indeed....
He thought about adding 'UniqueType foo(...)' to the overload set, and then
inspecting if overload resolution for: foo(T) matches that sentinel
function; but this requires sizeof() to accept 'foo(T)', which it doesn't
since its type is 'void'.
I still believe that allowing sizeof() to accept 'void' is not a good idea,
but I'd like to know how to solve this rather general problem: How can I use
an overloaded function if it is overloaded or else something else...
OTOH, to get out of this specific problem with a change in the design, I
would:
a) not use overloaded functions but template functions.
b) change the signature of 'xmlWriteImpl()' to return 'bool'. All overloads
returns 'true' while the default returns 'false'.
And I would definitely NOT have the default xmlWriteImpl() throw some
specific exception, which is a solution that would "work", but is not
recommended! ( I mention this just in case someone figures this out and
think it is a good idea)
--
Fernando Cacciola
Sierra s.r.l.
fcac...@gosierra.com
www.gosierra.com
Exactly!
> How do I know whether there exist an overload for an arbitrary type T
> ?
That's the problem!
> OTOH, to get out of this specific problem with a change in the design,
> I
> would:
>
> a) not use overloaded functions but template functions.
Doesn't work in my case, since I want to take advantage of polymorphism.
With template specialization you've to deal with any specific type of a
given hierachy. It's not sufficent to write an specialization for
"Base".
> b) change the signature of 'xmlWriteImpl()' to return 'bool'. All
> overloads returns 'true' while the default returns 'false'.
I don't like that solutions for too reasons.
1) You make a runtime check, when a compile-time check would be
sufficent.
2) I don't like function that return bool as a side-effect. I fear
clients could think it's a return code, and they have to return true if
successful and false if not (or was it the other way around?). If a
client returns false on failure, I would call flattenImpl (the
default-implementation of xmlWriteImpl), thinking "Oh, well,
xmlWriteImpl seems not to be implemtented".
So I think requiring xmlWriteImpl to return ostream& is the best
solution possible within the language, because:
1) the compile-time check works fine this way
2) You can't force xmlWriteImpl to return void, but you can force
xmlWriteImpl to return ostream&, which means if they return ostream&,
they can't return any unwanted errorcodes.
With a typeof operator all this would be more convinient.
Tim