假设您有一些目标类,其中包含一些方法:
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返回类型的方法:
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 return类型只是复制工作的两倍。
无论如何都要避免对void返回类型进行第二次专门化吗?
答案 0 :(得分:4)
您可以使用Return
并专门处理operator()
。无需复制整个模板。
// 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;
};
答案 1 :(得分:2)
不,绝对没有办法传递void
。这是语言的不规范。
函数参数列表(void)
被翻译为()
。 Bjarne更喜欢后者和前者,并且不情愿地允许C约定作为一种非常有限的句法糖。你甚至不能替换void
的typedef别名,你肯定不能有任何其他参数。
我个人认为这是一个坏主意。如果您可以编写void(expr)
,那么您应该能够“初始化”类型为void
的匿名参数。如果你还可以编写一个具有任意数量的void
参数的函数,那么就有办法以未指定的顺序执行许多表达式,这将以某种方式表达并发性。
至于处理不同大小的参数列表(也称为可变参数),在开始尝试学习Boost预处理器之前,请参阅C ++ 0x中的可变参数模板。