在 C++ 中使用“void”模板参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13372173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using 'void' template arguments in C++
提问by Nick Hutchinson
Take the following minimal example:
以以下最小示例为例:
using Type1 = std::function<void(void)>;
template <typename T>
using Type2 = std::function<void(T)>;
Type1 whyDoesThisWork;
Type2<void> andYetThisDoesNot;
If the second type alias, I get the error "Argument may not have 'void' type". (I tested with Xcode 4.5, Clang/c++11/libc++, OS X 10.7.)
如果是第二种类型的别名,我会收到错误“参数可能没有 'void' 类型”。(我使用 Xcode 4.5、Clang/c++11/libc++、OS X 10.7 进行了测试。)
I find this curious: I would have expected Type1
and Type2<void>
to behave identically. What's going on here? And is there a way to rewrite the second type alias so I canwrite Type2<void>
and get std::function<void(void)>
instead of an error?
我觉得这很奇怪:我会期望Type1
并Type2<void>
表现出相同的行为。这里发生了什么?有没有办法重写第二种类型的别名,以便我可以编写Type2<void>
和获取std::function<void(void)>
而不是错误?
EditI should probably add that the reason I want this is to allow for something like the following:
编辑我可能应该补充一点,我想要这样做的原因是允许以下内容:
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())>
becomes Continuation<void>
and I get the error.
Continuation<decltype(someFunc())>
变成了Continuation<void>
,我得到了错误。
采纳答案by Yakk - Adam Nevraumont
The short answer is "templates are not string substitution". void f(void)
has meaning only so far as it is an alias for void f()
in C++, in order to be backwards compatible with C.
简短的回答是“模板不是字符串替换”。 void f(void)
仅在它是void f()
C++ 中的别名时才有意义,以便向后兼容 C。
The first step is to use variadics, as noted elsewhere.
第一步是使用可变参数,如别处所述。
The second step is figuring out how to map void
returning functions to ... well, maybe something like std::function<void()>
, or maybe something else. I say maybe something else because unlike the other cases, you cannot call std::function<void()> foo; foo( []()->void {} );
-- it isn't a true continuation.
第二步是弄清楚如何将void
返回函数映射到......好吧,可能是类似的东西std::function<void()>
,或者可能是其他东西。我说也许是别的,因为与其他情况不同,你不能打电话std::function<void()> foo; foo( []()->void {} );
——这不是真正的延续。
Something like this maybe:
可能是这样的:
template<typename T>
struct Continuation
{
typedef std::function<void(T)> type;
};
template<>
struct Continuation<void>
{
typedef std::function<void()> type;
};
then use it like this:
然后像这样使用它:
auto someFunc = []()->void {};
Continuation<decltype(someFunc())>::type c;
which gives you the type you want. You could even add in an apply to continuation:
这给你你想要的类型。你甚至可以添加一个 apply to continuation:
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();
}
};
which lets you apply a continuation to an execution of a function uniformly if the incoming type is a void or if it is a non-void type.
如果传入类型是 void 或非 void 类型,它允许您统一地将延续应用于函数的执行。
However, I would ask "why would you want to do this"?
但是,我会问“您为什么要这样做”?
回答by Kerrek SB
I don't have an actual answer, only what I said in the comment: You can't have void
as a function type, as in:
我没有实际的答案,只有我在评论中所说的:您不能将其void
作为函数类型,例如:
int foo(int, char, void, bool, void, void); // nonsense!
I believe that T(void)
is only allowed as a compatibility notation for C (which distinguishes declarationsand prototypes, very differently from C++, and which needs to be able to say "no arguments").
我相信这T(void)
仅被允许作为 C 的兼容性符号(它区分声明和原型,与 C++ 非常不同,并且需要能够说“无参数”)。
So, the solution should be variadic:
因此,解决方案应该是可变参数:
template <typename ...Args> using myType = std::function<void(Args...)>;
That way you can properly have no arguments:
这样你就可以正确地没有参数:
myType<> f = []() { std::cout << "Boo\n"; }
回答by James McNellis
Several answers already explain the rationale. To add to those answers, the specification says (C++11 §8.3.5[dcl.func]/4):
几个答案已经解释了基本原理。为了补充这些答案,规范说(C++11 §8.3.5[dcl.func]/4):
A parameter list consisting of a single unnamed parameter of non-dependent type
void
is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cvvoid
.
由单个非依赖类型的未命名参数组成的参数列表
void
等效于空参数列表。除了这种特殊情况,参数不应具有cv类型void
。
In your Type2
example, the T
in void(T)
is a dependent type--it depends on a template parameter.
在您的Type2
示例中,T
invoid(T)
是依赖类型——它依赖于模板参数。
回答by Benjamin Lindley
When a function is declared to take a parameter of type void
, as in std::function<void(void)>
, that is really just a goofy way of saying that it takes zero parameters. But the way you've declared Type2 is as a std::function
with a signature that returns nothing (void), but that takes 1 parameter. void is not a type that can be used as a parameter, it is just a way of declaring that there are no parameters. So it doesn't work with Type2, because that requires an actual type that can be used as a parameter.
当一个函数被声明为接受类型void
为的参数时,如在 中std::function<void(void)>
,这实际上只是一种愚蠢的说法,即它接受零参数。但是您声明 Type2 的方式是std::function
带有不返回任何内容(无效)的签名,但它需要 1 个参数。void 不是可以用作参数的类型,它只是声明没有参数的一种方式。所以它不适用于 Type2,因为它需要一个可以用作参数的实际类型。
回答by count0
Void can be interpreted as an empty parameter if you pass it to a function. You're not using a void pointer after all so
如果将 Void 传递给函数,则可以将其解释为空参数。毕竟你没有使用空指针
void func (void)
becomes
变成
void func ()