在C ++中使用'void'模板参数

时间:2012-11-14 02:27:59

标签: c++ templates c++11 std-function

采用以下最小例子:

using Type1 = std::function<void(void)>;

template <typename T>
using Type2 = std::function<void(T)>;

Type1 whyDoesThisWork;
Type2<void> andYetThisDoesNot;

如果是第二种类型的别名,我会收到错误“Argument may not have'void'type”。 (我使用Xcode 4.5,Clang / c ++ 11 / libc ++,OS X 10.7进行了测试。)

我觉得这很奇怪:我希望Type1Type2<void>的行为相同。这里发生了什么?有没有办法重写第二种类型的别名,所以我可以Type2<void>并获取std::function<void(void)>而不是错误?

编辑我应该补充一点,我想要的原因是允许以下内容:

template <typename ... T>
using Continuation = std::function<void(T...)>;

auto someFunc = []() -> void {
  printf("I'm returning void!\n");
};

Continuation<decltype(someFunc())> c;

Continuation<decltype(someFunc())>变为Continuation<void>,我收到错误。

5 个答案:

答案 0 :(得分:12)

我没有实际答案,只有我在评论中说的内容:您不能将void作为函数类型,如:

int foo(int, char, void, bool, void, void);     // nonsense!

我认为T(void)仅允许作为C的兼容性表示法(区分声明原型,与C ++完全不同,并且需要能够说“没有争论”)。

所以,解决方案应该是可变的:

template <typename ...Args> using myType = std::function<void(Args...)>;

这样你就可以正确地拥有无参数

myType<> f = []() { std::cout << "Boo\n"; }

答案 1 :(得分:12)

简短的回答是“模板不是字符串替换”。 void f(void)只有在C ++中为void f()的别名才有意义,以便向后兼容C。

第一步是使用可变参数,如其他地方所述。

第二步是弄清楚如何将void返回函数映射到......好吧,也许像std::function<void()>,或者其他东西。我说也许别的东西,因为与其他情况不同,你不能打电话给std::function<void()> foo; foo( []()->void {} ); - 这不是真正的延续。

这样的事情可能是:

template<typename T>
struct Continuation
{
  typedef std::function<void(T)> type;
};

template<>
struct Continuation<void>
{
  typedef std::function<void()> type;
};

然后像这样使用它:

auto someFunc = []()->void {};
Continuation<decltype(someFunc())>::type c;

为您提供所需的类型。你甚至可以添加申请继续:

template<typename T>
struct Continuation
{
  typedef std::function<void(T)> type;

  template<typename func, typename... Args>
  static void Apply( type const& cont, func&& f, Args... args)
  {
    cont( f(args...) );
  }
};

template<>
struct Continuation<void>
{
  typedef std::function<void()> type;
  template<typename func, typename... Args>
  static void Apply( type const& cont, func&& f, Args... args)
  {
    f(args...);
    cont();
  }
};

,如果传入类型为void或者它是非void类型,则允许您对函数的执行应用延续。

但是,我会问“你为什么要这样做?”

答案 2 :(得分:5)

几个答案已经解释了理由。为了增加这些答案,规范说明了(C ++11§8.3.5[dcl.func] / 4):

  

由非依赖类型void的单个未命名参数组成的参数列表是   相当于一个空参数列表。除了这种特殊情况,参数不应具有 cv void类型。

Type2示例中,T中的void(T)依赖类型 - 它取决于模板参数。

答案 3 :(得分:3)

当声明一个函数采用void类型的参数时,就像std::function<void(void)>一样,这实际上只是一种愚蠢的方式,它说它需要零参数。但是你声明Type2的方式是std::function,其签名不返回任何内容(void),但需要1个参数。 void不是可以用作参数的类型,它只是一种声明没有参数的方法。所以它不适用于Type2,因为它需要一个可以用作参数的实际类型。

答案 4 :(得分:0)

如果将Void传递给函数,则可以将其解释为空参数。毕竟你没有使用空指针

void func (void)

变为

void func ()