首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用作模板化函数输入的函数的void返回值被视为参数

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

Stack Overflow用户
提问于 2010-09-06 10:04:17
回答 2查看 1.4K关注 0票数 7

假设你有一些目标类和一些方法:

代码语言:javascript
复制
class Subject
{
public:
  void voidReturn() { std::cout<<__FUNCTION__<<std::endl; }
  int  intReturn()  { std::cout<<__FUNCTION__<<std::endl; return 137; }
};

和一个值类(在概念上类似于Boost.Any):

代码语言:javascript
复制
struct Value
{
  Value() {}
  Value( Value const & orig ) {}
  template< typename T > Value( T const & val ) {}
};

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

代码语言:javascript
复制
Subject subject;
Value intval( subject.intReturn() );
Value voidVal( subject.voidReturn() );  // compilation error

我在VC++2008中得到以下错误:

代码语言:javascript
复制
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:

代码语言:javascript
复制
/c/sandbox/dev/play/voidreturn/vr.cpp:67: error: invalid use of void expression

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

代码语言:javascript
复制
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)的方法上使用此方法类将如下所示:

代码语言:javascript
复制
Method< Subject, int () > intMeth( &subject, &Subject::intReturn );
Value intValue = intMeth();

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

代码语言:javascript
复制
Method< Subject, void () > voidMeth( &subject, &Subject::voidReturn );
Value voidValue = voidMeth();

产生与上面类似的错误。

一种解决方案是进一步部分专门化void返回类型的方法:

代码语言:javascript
复制
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个签名参数的方法类进行专门化,这已经涉及到大量的代码重复(希望Boost.Preprocessor可以在这里提供帮助),然后为空返回类型添加专门化只会使重复的工作加倍。

有没有什么方法可以避免这种对void返回类型的第二种专门化?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-09-11 19:20:18

您可以使用Return,只需专门处理operator()即可。不需要复制整个模板。

代码语言:javascript
复制
// 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;
};
票数 4
EN

Stack Overflow用户

发布于 2010-09-06 11:48:01

不,绝对没有办法传递void。这是语言中的一种不规范现象。

将函数参数列表(void)转换为()。Bjarne更喜欢后者而不是前者,并不情愿地允许C约定作为一种非常有限的语法糖。您甚至不能替换void的类型定义别名,当然也不能有任何其他参数。

我个人认为这是一个坏主意。如果您可以编写void(expr),那么您应该能够“初始化”void类型的匿名参数。如果您还可以编写具有任意数量的void参数的函数,那么就有办法以未指定的顺序执行许多表达式,这将在某种程度上表示并发性。

至于处理不同大小的参数列表(也称为可变参数列表),在开始学习Boost预处理器之前,请参阅C++0x中的可变模板。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3648638

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档