采用以下最小例子:
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进行了测试。)
我觉得这很奇怪:我希望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;
Continuation<decltype(someFunc())>
变为Continuation<void>
,我收到错误。
答案 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
的单个未命名参数组成的参数列表是 相当于一个空参数列表。除了这种特殊情况,参数不应具有 cvvoid
类型。
在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 ()