我正在尝试编写一个类,该类可以稍后调用无参数的lambda。我期待C ++ 17类模板自变量的推导避免需要工厂函数。但是,尝试实例化对象而不指定类型失败。我可以使用工厂功能,但我想了解为什么会发生这种情况。
我正在使用VC ++ 2017,并且已启用C ++ 17工具集。这是预期的行为吗?为什么?由于模板函数和模板类的类型推导规则不同,是否可以避免工厂函数或是否需要工厂函数?任何帮助都将得到感谢。
template <typename F>
class WillInvoke
{
public:
WillInvoke(std::decay_t<F> f) : f(std::move(f)) { }
void CallNow() { f(); }
private:
std::decay_t<F> f;
};
template <typename F>
WillInvoke<F> make_WillInvoke(F && f)
{
return WillInvoke<F>(std::forward<F>(f));
}
int main()
{
// OK
auto w = make_WillInvoke([](){ std::cout << "Hello World"; });
w.CallNow();
// Won't compile
WillInvoke w2([](){ std::cout << "Hello World"; }); // No instance of constructor matches argument list
w2.CallNow();
}
答案 0 :(得分:5)
这是因为诸如std::decay<T>::type
之类的成员类型别名不可抵扣。
template<typename T>
void call_me(std::decay_t<T>) {}
// won't work :(
// call_me(1);
我不认为您的班级应该削弱这种类型。相反,您的类应声明它需要一个对象类型,然后将衰变移入make函数:
template <typename F> // requires std::is_object_v<F>
class WillInvoke
{
static_assert(std::is_object_v<F>,
"WillInvoke requires F to be an object type"
);
public:
WillInvoke(F f) : f(std::move(f)) { }
void CallNow() { f(); }
private:
F f;
};
template <typename F>
auto make_WillInvoke(F && f) -> WillInvoke<std::decay_t<F>>
{
return WillInvoke<std::decay_t<F>>(std::forward<F>(f));
}
有趣的是,在C ++ 20中,您可以取消注释需求,并让编译器在调用站点中强制执行该要求。