如何在声明和定义中拆分静态lambda
How to split static lambda in declaration and definition?
我在类中有一个静态lambda,在标题文件中声明和定义为:
class A final {
// inline could be removed of course for splitting
static inline auto foo = [](auto& param1, auto& param2 auto& param3) {
// do stuff
return;
}
}
// compiles fine
使用静态变量,例如static int x = 42
,我可以将声明和定义分开:
// bar.h:
class Bar {
static int x;
}
// bar.cpp:
#include "bar.h"
int Bar::x = 42;
如何用上述lambda进行同一件事?当然可以更改签名。
基本问题是每个lambda表达式都有其独立的类型(另请参见此答案)。由于您需要知道要声明变量的类型,并且您需要知道lambda表达式以了解其类型,因此无需声明变量以保持lambda表达式的结果而不知道lambda表达式本身。
只要您知道这两个地方的lambda表达式,就可以声明一个变量以保持lambda并分别定义变量。例如:
inline auto makeFoo() {
return [](auto& param1, auto& param2, auto& param3) {
// do stuff
return;
};
}
class A final {
static decltype(makeFoo()) foo;
};
decltype(makeFoo()) A::foo = makeFoo();
但是,不可能将变量的声明与lambda表达式分开(即,您不能仅在将变量定义的文件中使用lambda表达式)。
未捕获任何内容的lambda表达式可以转换为指针转换为函数。如果您不需要lambda来捕获任何内容(例如在示例中),并且只需要一个特定签名的可召唤,则可以简单地将A::foo
声明为功能指针类型,并使用匹配的lambda来初始化A::foo
的定义:
class A final {
static void (*foo)(int&, float&, double&);
};
void (*A::foo)(int&, float&, double&) = [](auto& param1, auto& param2, auto& param3) {
// do stuff
return;
};
如果您确实需要一个通用的lambda(带有auto
参数的一个),那么您的示例建议也无法正常工作,而且您很可能是不运气的。拥有通用的呼叫操作员意味着您的闭合类型的operator ()
函数必须是功能模板。具有operator ()
功能模板意味着必须知道其定义才能真正拨打电话。即使您写了自己的课程而不是使用lambda表达式,也无法让任何人在不知道其定义的情况下调用通用operator ()
。您所能做的就是为您需要支持的所有签名和分别定义这些签名的operator ()
模板的显式实例。但这再次要求您实际上知道您需要可调用的哪些具体签名来支持…
如何用上面的lambda进行同一件事?
你不能。您必须始终声明变量的类型。如果您在声明变量后定义了lambda,则不能从初始评估器中推导声明的类型。但是,您不能在定义lambda之前指的类型,因为该类型是匿名的。
而不是lambda(即匿名函数对象),您可以简单地使用命名类型的函数对象。然后,您可以将功能定义分开。另外,您必须声明该函数的返回类型,因为如果没有函数的定义,就无法推导它:
class A final {
constexpr struct Foo {
template<class Param1, class Param2, class Param3>
void operator()(Param1&, Param2&, Param3&) const;
} foo{};
};
但是,正如您可能注意到的那样,该功能实际上是函数模板。这是因为您在lambda中使用auto
参数。如果您想定义标题外部的模板,则必须将实例限制为有限的集合,并明确实例化定义模板的地方:
// the definition
template<class Param1, class Param2, class Param3>
void A::Foo::operator()(Param1&, Param2&, Param3&) const {
// do stuff
return;
}
// explicit instantiations
template void A::Foo::operator()<int, int, int>(int&, int&, int&) const;
template void A::Foo::operator()<int, double, float>(int&, double&, float&) const;
如果您尝试使用未实例化的参数,则在未定义模板的翻译单元中,则会有一个链接器错误。
如果您想保持参数不受限制,那么您的要求矛盾。仅通过定义标题中的模板才能实现不受约束的模板。
另一方面,您可能需要考虑是否首先需要功能对象。您没有证明自己的需求。上面的示例同样可以使其成为静态成员函数(模板)而不是函数对象。
您仍然可以以旧方式创建函子:
struct Foo
{
template <typename T1, typename T2, typename T3>
void operator ()(T1& param1, T2& param2, T3& param3) const;
};
template <typename T1, typename T2, typename T3>
void Foo::operator ()(T1& param1, T2& param2, T3& param3) const
{
/*..*/
}
class A final {
// inline could be removed of course for splitting
static const Foo foo;
};
// in .cpp
const Foo A::foo{};
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- #为""定义宏;静态";针对不同的上下文
- cmake如何在fedora工作站中找到boost静态库包
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- cmake在我的项目中所需的所有静态库都不成功
- C++从另一个类访问公共静态向量的正确方法是什么
- 基于boost的程序的静态链接——zlib问题
- 在静态库中嵌入类方法
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 如何在C++中获得"静态纯虚拟"功能?
- 私有类型的静态常量成员
- 使用gcc从静态链接的文件中查找可选符号
- C++将向量的向量拆分为向量的N个子向量
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 如何在C++中使用非静态成员函数作为回调函数
- 如何在标题和CPP之间拆分静态/模板类
- 如何在声明和定义中拆分静态lambda
- C++ OpenMP:将 for 循环拆分为静态偶数块,并在最后连接数据
- 无法拆分头文件和源文件中具有静态成员函数的类