用作模板函数输入的函数的 void 返回值被视为参数
假设您有一些带有一些方法的目标类:
class Subject
{
public:
void voidReturn() { std::cout<<__FUNCTION__<<std::endl; }
int intReturn() { std::cout<<__FUNCTION__<<std::endl; return 137; }
};
和一个 Value 类(在概念上与 Boost.Any 类似):
struct Value
{
Value() {}
Value( Value const & orig ) {}
template< typename T > Value( T const & val ) {}
};
我想使用 Subject 类中的方法生成一个 Value 对象:
Subject subject;
Value intval( subject.intReturn() );
Value voidVal( subject.voidReturn() ); // compilation error
我在 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
和 gcc 4.4.3:
/c/sandbox/dev/play/voidreturn/vr.cpp:67: error: invalid use of void expression
当您想在模板类中使用它时,上下文是这样的:
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;
};
在返回某些内容(即 intReturn)的方法上使用此 Method 类看起来像:
Method< Subject, int () > intMeth( &subject, &Subject::intReturn );
Value intValue = intMeth();
但是,使用 voidReturn 执行此操作方法:
Method< Subject, void () > voidMeth( &subject, &Subject::voidReturn );
Value voidValue = voidMeth();
产生与上面类似的错误。
一种解决方案是进一步部分专门化 void 返回类型的 Method:
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;
};
除了感觉丑陋之外,我还想专门化 X 个签名参数的 Method 类,这已经涉及大量代码重复(希望 Boost.Preprocessor 可以在这里提供帮助),然后添加 void 返回类型的专门化只会使重复工作加倍。
是否有办法避免对 void 返回类型进行第二次专门化?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用
Return
并专门化operator()
处理。无需复制整个模板。You could use
Return
and just specializeoperator()
handling. No need to duplicate the whole template.不,绝对没有办法传递
void
。这是语言中的不规则现象。函数参数列表
(void)
被翻译为()
。 Bjarne 更喜欢后者而不是前者,并且不情愿地允许 C 约定作为一种非常有限的语法糖。您甚至不能替换void
的 typedef 别名,并且您当然不能有任何其他参数。我个人认为这是一个坏主意。如果您可以编写
void(expr)
,那么您应该能够“初始化”void
类型的匿名参数。如果您还可以编写一个具有任意数量的 void 参数的函数,那么就会有一种方法以未指定的顺序执行多个表达式,这会以某种方式表达并发性。至于处理不同大小的参数列表(也称为可变参数),请在开始尝试学习 Boost 预处理器之前参阅 C++0x 中的可变参数模板。
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 ofvoid
, 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 typevoid
. If you could also write a function with an arbitrary number ofvoid
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.