Void returns a value from a function used as an input parameter to a template function, considered as a parameter

Let's say you have some kind of 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 the Value class (similar to Boost.Any):

 struct Value { Value() {} Value( Value const & orig ) {} template< typename T > Value( T const & val ) {} }; 

And I want to create a Value object using the method from the Subject class:

 Subject subject; Value intval( subject.intReturn() ); Value voidVal( subject.voidReturn() ); // compilation error 

In VC ++ 2008, the following errors occur:

 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 template:

 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 for a method returning something (namely intReturn) would look like this:

 Method< Subject, int () > intMeth( &subject, &Subject::intReturn ); Value intValue = intMeth(); 

However, by doing this using the voidReturn method:

 Method< Subject, void () > voidMeth( &subject, &Subject::voidReturn ); Value voidValue = voidMeth(); 

gives similar errors as stated above.

One solution is to further partially specialize the method for 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; }; 

Also, it's just ugly, I also want to specialize the Method class for X signature parameter numbers, which already includes a lot of code duplication (hopefully Boost.Preprocessor can help here), and then adding specialization for void return types only double that effort duplication.

Anyway, to avoid this second specialization for void return types?

+6
c ++ generic-programming templates
source share
2 answers

You can use Return and just specialize operator() handling. No need to duplicate the whole template.

 // I think it a shame if c++0x really gets rid of std::identity. It 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; }; 
+4
source share

No, there is no way to pass void . This is uneven in the language.

The argument list of the function (void) translates to () . Bjarne prefers the latter to the former and ruthlessly admits Convention C as a very limited kind of syntactic sugar. You cannot even replace the typedef alias with void , and of course you will not have any other arguments.

I personally think this is a bad idea. If you can write void(expr) , then you can "initialize" an anonymous argument of type void . If you could write a function with an arbitrary number of void arguments, there would be a way to execute multiple expressions in an unspecified order, which would express concurrency in some way.

For handling argument lists of different sizes (also known as variadic), see Variadic templates in C ++ 0x before you start trying to learn Preprocessor.

+2
source share

All Articles