用作模板化函数输入的函数的void返回值被视为参数

Chr*_*ris 6 c++ templates generic-programming

假设您有一些目标类,其中包含一些方法:

class Subject
{
public:
  void voidReturn() { std::cout<<__FUNCTION__<<std::endl; }
  int  intReturn()  { std::cout<<__FUNCTION__<<std::endl; return 137; }
};
Run Code Online (Sandbox Code Playgroud)

和Value类(概念类似于Boost.Any):

struct Value
{
  Value() {}
  Value( Value const & orig ) {}
  template< typename T > Value( T const & val ) {}
};
Run Code Online (Sandbox Code Playgroud)

我想使用Subject类中的方法生成一个Value对象:

Subject subject;
Value intval( subject.intReturn() );
Value voidVal( subject.voidReturn() );  // compilation error
Run Code Online (Sandbox Code Playgroud)

我在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
Run Code Online (Sandbox Code Playgroud)

和gcc 4.4.3:

/c/sandbox/dev/play/voidreturn/vr.cpp:67: error: invalid use of void expression
Run Code Online (Sandbox Code Playgroud)

这个上下文是你想在模板化的类中使用它的时候:

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;
};
Run Code Online (Sandbox Code Playgroud)

在返回某些东西的方法(即intReturn)上使用此Method类看起来像:

Method< Subject, int () > intMeth( &subject, &Subject::intReturn );
Value intValue = intMeth();
Run Code Online (Sandbox Code Playgroud)

但是,使用voidReturn方法执行此操作:

Method< Subject, void () > voidMeth( &subject, &Subject::voidReturn );
Value voidValue = voidMeth();
Run Code Online (Sandbox Code Playgroud)

产生与上述类似的错误.

一种解决方案是进一步部分地专门化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;
};
Run Code Online (Sandbox Code Playgroud)

除了它只是感觉丑陋之外,我还想为X数量的签名参数专门化Method类,这已经涉及很多代码重复(希望Boost.Preprocessor可以在这里帮助),然后为void返回类型添加一个特化只需将复制工作加倍.

反正有没有为void返回类型避免第二次专门化?

Joh*_*itb 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;
};
Run Code Online (Sandbox Code Playgroud)