Say you have some target class with some methods on it:
class Subject
{
public:
void voidReturn() { std::cout<<__FUNCTION__<<std::endl; }
int intReturn() { std::cout<<__FUNCTION__<<std::endl; return 137; }
};
And a Value class (similar in concept to Boost.Any):
struct Value
{
Value() {}
Value( Value const & orig ) {}
template< typename T > Value( T const & val ) {}
};
And I want to produce a Value object using a method from the Subject class:
Subject subject;
Value intval( subject.intReturn() );
Value voidVal( subject.voidReturn() ); // compilation error
I get the following errors in VC++2008:
error C2664: 'Value::Value(const Value &)' : cannot convert parameter 1 from 'void' to 'const Value &'
Expressions of type void cannot be converted to other types
and gcc 4.4.3:
/c/sandbox/dev/play/voidreturn/vr.cpp:67: error: invalid use of void expression
The context for this is when you want to use it inside a templated class:
template< typename Host, typename Signature > class Method;
// Specialization for signatures with no parameters
template< typename Host, typename Return >
class Method< Host, Return () >
{
public:
typedef Return (Host::*MethodType)();
Method( Host * host, MethodType method ) : m_Host(host), m_Method(method) {}
Value operator()() { return Value( (m_Host->*m_Method)() ); }
private:
Host * m_Host;
MethodType m_Method;
};
Using this Method class on the method which returns something (namely intReturn) would look like:
Method< Subject, int () > intMeth( &subject, &Subject::intReturn );
Value intValue = intMeth();
However, doing this with the voidReturn method:
Method< Subject, void () > voidMeth( &subject, &Subject::voidReturn );
Value voidValue = voidMeth();
yields similar errors as above.
One solution is to further partially specialize Method for void return types:
template< typename Host >
class Method< Host, void () >
{
public:
typedef void Return;
typedef Return (Host::*MethodType)();
Method( Host * host, MethodType method ) : m_Host(host), m_Method(method) {}
Value operator()() { return (m_Host->*m_Method)(), Value(); }
private:
Host * m_Host;
MethodType m_Method;
};
Besides it just feeling ugly, I'm also wanting to specialize the Method class for X numbers of signature parameters, which already involves a lot of code duplication (hopefuly Boost.Preprocessor can help here), and then adding a specialization for void return types just doubles that duplication effort.
Is there anyway to avoid this second specialization for void return types?
In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value. You may or may not use the return statement, as there is no return value.
void (C++) When used as a function return type, the void keyword specifies that the function doesn't return a value. When used for a function's parameter list, void specifies that the function takes no parameters. When used in the declaration of a pointer, void specifies that the pointer is "universal."
A void function with value parameters are declared by enclosing the list of types for the parameter list in the parentheses. To activate a void function with value parameters, we specify the name of the function and provide the actual arguments enclosed in parentheses.
In UML models, template parameters are formal parameters that once bound to actual values, called template arguments, make templates usable model elements. You can use template parameters to create general definitions of particular types of template.
You could use Return
and just specialize operator()
handling. No need to duplicate the whole template.
// I think it's a shame if c++0x really gets rid of std::identity. It's soo useful!
template<typename> struct t2t { };
// Specialization for signatures with no parameters
template< typename Host, typename Return >
class Method< Host, Return () >
{
public:
typedef Return (Host::*MethodType)();
Method( Host * host, MethodType method ) : m_Host(host), m_Method(method) {}
Value operator()() { return call(t2t<Return>()); }
private:
Value call(t2t<void>) { return Value(); }
template<typename T>
Value call(t2t<T>) { return Value((m_Host->*m_Method)()); }
private:
Host * m_Host;
MethodType m_Method;
};
No, there is absolutely no way to pass a void
. It is an irregularity in the language.
The function argument list (void)
is translated as ()
. Bjarne prefers the latter to the former, and begrudgingly allowed the C convention as a very limited kind of syntactic sugar. You can't even substitute a typedef alias of void
, and you certainly can't have any other arguments.
I personally think this is a bad idea. If you can write void(expr)
, then you should be able to "initialize" an anonymous argument of type void
. If you could also write a function with an arbitrary number of void
arguments, there would be a way to execute a number of expressions in unspecified order, which would express concurrency in a way.
As for handling different-sized argument lists (also known as variadic), see variadic templates in C++0x before you start trying to learn Boost Preprocessor.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With