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

Using 'void' template arguments in C++

本文关键字:void 参数 C++      更新时间:2023-10-16

举以下最小的例子:

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

如果是第二个类型别名,我会收到错误"参数可能没有'void'类型"。(我用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>,我得到错误。

简短的回答是"模板不是字符串替换"。 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 类型时将延续统一应用于函数的执行。

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

我没有实际的答案,只有我在评论中所说的: 您不能将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 << "Boon"; }

有几个答案已经解释了基本原理。 为了补充这些答案,规范说(C++11 §8.3.5[dcl.func]/4):

由非依赖类型void的单个未命名参数组成的参数列表为 等效于空参数列表。除此特殊情况外,参数不得具有 cv void 类型。

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

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

如果将

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

void func (void)

成为

void func ()