C++17 中的模板化 lambda 没有自动参数
Templated lambdas in C++17 without an auto argument
我有一个 class Derived
继承自 class Base<ResourceType>
:
template <class ResourceType>
class Base {
protected:
ResourceType* resource;
public:
void set_resource(ResourceType* resource) {
this->resource = resource;
}
};
template <class ResourceType>
class Derived : public Base<ResourceType> {
public:
using Base<ResourceType>::resource;
void print () {
std::cout << *resource << std::endl;
}
};
我想创建一个工厂来创建 Derived
类型的对象。我当然可以用函数来做到这一点:
template <typename ResourceType>
auto derived_factory () {
return new Derived<ResourceType>();
}
auto derived = *(derived_factory<int>());
但是,我无法为工厂编写 lambda 函数。如果我使用 auto 关键字接受模板参数,我可以编写模板化的 lambda 函数,但在这里我只想使用模板来确定 return 类型。以下失败:
auto derived_factory = []<typename ResourceType>() {
return new Derived<ResourceType>();
};
auto derived = *(derived_factory<int>());
错误:
inherit_unknown_type.cpp: In function ‘int main()’:
inherit_unknown_type.cpp:27:36: error: expected primary-expression before ‘int’
auto derived = *(derived_factory<int>());
^~~
inherit_unknown_type.cpp:27:36: error: expected ‘)’ before ‘int’
我只是错误地调用了 lambda 吗?还是我必须等待 C++20
?
lambda 表达式中的模板参数列表是 C++20 feature.
(事实上,我的 GCC 在诊断中说:error: lambda templates are only available with -std=c++2a or -std=gnu++2a [-Wpedantic]
)
但您不必等待 C++20,GCC 8 已经 supported 带有 -std=c++2a
标志。
并且您必须更改调用语法:您需要 derived_factory.operator()<int>()
.
而不是 derived_factory<int>()
作为替代方案(如果您不想要免费功能),我建议使用标签分发的变体:
auto derived_factory = [](auto tag) {
return new Derived<typename tag::type>();
};
template <typename T> struct tag_type {using type = T;};
// Usage:
derived_factory(tag_type<int>{})
此外,即使您以某种方式编译它,这一行:
auto derived = *(derived_factory<int>());
无论如何都会导致内存泄漏。为避免这种情况,您应该将结果存储为指针或引用。或者更好的是,使用智能指针。
等待 C++20,您可以return 来自模板的 lambda class
template <typename ResourceType>
auto make_derived_factory ()
{ return []{ return new Derived<ResourceType>{}; }; }
auto derived = make_derived_factory<int>();
int main ()
{
auto df { derived() };
}
上面的方法行不通,但这行:
auto derived_factory = [](auto tag)
{
return new Derived<decltype(tag)::type>();
};
template <typename T> struct tag_type {using type = T;};
// Usage:
derived_factory(tag_type<int>{})
我有一个 class Derived
继承自 class Base<ResourceType>
:
template <class ResourceType>
class Base {
protected:
ResourceType* resource;
public:
void set_resource(ResourceType* resource) {
this->resource = resource;
}
};
template <class ResourceType>
class Derived : public Base<ResourceType> {
public:
using Base<ResourceType>::resource;
void print () {
std::cout << *resource << std::endl;
}
};
我想创建一个工厂来创建 Derived
类型的对象。我当然可以用函数来做到这一点:
template <typename ResourceType>
auto derived_factory () {
return new Derived<ResourceType>();
}
auto derived = *(derived_factory<int>());
但是,我无法为工厂编写 lambda 函数。如果我使用 auto 关键字接受模板参数,我可以编写模板化的 lambda 函数,但在这里我只想使用模板来确定 return 类型。以下失败:
auto derived_factory = []<typename ResourceType>() {
return new Derived<ResourceType>();
};
auto derived = *(derived_factory<int>());
错误:
inherit_unknown_type.cpp: In function ‘int main()’:
inherit_unknown_type.cpp:27:36: error: expected primary-expression before ‘int’
auto derived = *(derived_factory<int>());
^~~
inherit_unknown_type.cpp:27:36: error: expected ‘)’ before ‘int’
我只是错误地调用了 lambda 吗?还是我必须等待 C++20
?
lambda 表达式中的模板参数列表是 C++20 feature.
(事实上,我的 GCC 在诊断中说:error: lambda templates are only available with -std=c++2a or -std=gnu++2a [-Wpedantic]
)
但您不必等待 C++20,GCC 8 已经 supported 带有 -std=c++2a
标志。
并且您必须更改调用语法:您需要 derived_factory.operator()<int>()
.
derived_factory<int>()
作为替代方案(如果您不想要免费功能),我建议使用标签分发的变体:
auto derived_factory = [](auto tag) {
return new Derived<typename tag::type>();
};
template <typename T> struct tag_type {using type = T;};
// Usage:
derived_factory(tag_type<int>{})
此外,即使您以某种方式编译它,这一行:
auto derived = *(derived_factory<int>());
无论如何都会导致内存泄漏。为避免这种情况,您应该将结果存储为指针或引用。或者更好的是,使用智能指针。
等待 C++20,您可以return 来自模板的 lambda class
template <typename ResourceType>
auto make_derived_factory ()
{ return []{ return new Derived<ResourceType>{}; }; }
auto derived = make_derived_factory<int>();
int main ()
{
auto df { derived() };
}
上面的方法行不通,但这行:
auto derived_factory = [](auto tag)
{
return new Derived<decltype(tag)::type>();
};
template <typename T> struct tag_type {using type = T;};
// Usage:
derived_factory(tag_type<int>{})