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

Nic*_*son 20 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;
Run Code Online (Sandbox Code Playgroud)

如果第二个类型别名,我得到错误"参数可能没有'void'类型".(我使用Xcode 4.5,Clang/c ++ 11/libc ++,OS X 10.7进行了测试.)

我发现这很奇怪:我本来期望Type1并且Type2<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;
Run Code Online (Sandbox Code Playgroud)

Continuation<decltype(someFunc())>成为Continuation<void>,我得到了错误.

Ker*_* SB 12

我没有一个实际的答案,只有我在评论中说的:你不能void作为一个函数类型,如:

int foo(int, char, void, bool, void, void);     // nonsense!
Run Code Online (Sandbox Code Playgroud)

我认为T(void)只允许作为C的兼容性符号(它区分声明原型,与C++非常不同,并且需要能够说"没有参数").

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

template <typename ...Args> using myType = std::function<void(Args...)>;
Run Code Online (Sandbox Code Playgroud)

这样你就可以正确地没有参数:

myType<> f = []() { std::cout << "Boo\n"; }
Run Code Online (Sandbox Code Playgroud)

  • 抱歉,我不知何故无意中对此投了反对票,直到后来才注意到,但为时已晚,无法更改它。 (2认同)

Yak*_*ont 12

简短的回答是"模板不是字符串替换". void f(void)只有它是void f()C++中的别名才有意义,以便向后兼容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;
};
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

auto someFunc = []()->void {};
Continuation<decltype(someFunc())>::type c;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


Jam*_*lis 5

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

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

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