静态常量全局仿函数实例
Static const global functor instances
声明函数对象的全局实例以便我可以在整个程序中导入和使用实例作为可调用对象的最佳方法是什么?
具体来说,我创建了一个模板 class,用作共享指针的自定义删除器。需要使用引用指针的 "Free" 函数删除第三方库中的几种指针类型。 class 的实例使用要删除的指针的类型以及指向具有 Free 函数签名的函数的指针进行实例化。我将实例声明为 const,因为成员函数指针不需要更改。
template <class T>
class Deleter {
public:
typedef typename bool(CALLING_CONVENTION *DeleterFunc)(T**);
Deleter(DeleterFunc deleter) : deleter_(deleter) {}
void operator() (T* t) { if (t) { deleter_(&t) }
private:
DeleterFunc deleter_;
};
static const Deleter<I_x> x_deleter(FreeXInterface);
我的第一次尝试是为 .h 文件中的每个指针类型创建实例,但是如果我在其他代码中包含此头文件,这会导致多重定义的符号。所以我将实例的声明更改为 "static" 并且这编译并且似乎工作正常,但我看到警告这不是一个好主意(特别是如果对象属于名称空间)因为静态导致链接为仅文件,每个编译单元都有自己的副本。
我的问题是,如果我真的不关心它们是否是文件之间的同一实例,这有关系吗?我没有将其用作全局数据,函数对象实际上没有任何状态。如果将这些对象声明为静态,我会对线程化有任何顾虑吗?有没有更好的方法来实现这个而不使用 static 关键字?
好吧,您的链接器问题的基本答案在这里:How do I use extern to share variables between source files?不过,让我们尝试做得更好一点:您目前每次实例化函数时都必须引用删除函数,而不是根据类型自动选择。
当然我们经常根据类型选择类型:std::vector<int>
是能够容纳int
的动态数组。那里的链接不是一个大问题:一切都或多或少是内联的,每个提到 std::vector<int>::push_back()
的翻译单元都有自己的目标代码副本,以将一个 int 放入一个 int 向量中,并且链接器(有时)提供帮助通过删除重复的实例化。但是这里我们想要一个对象,而不是类型。
那么模板和全局对象之间的中间点是什么?模板化 classes 的静态成员!检查一下:
// Deleter.h
typedef typename bool(CALLING_CONVENTION *DeleterFunc)(T**);
template <class T>
class Deleter {
public:
static DeleterFunc s_deleterFunc;
void operator() (T* t) {
if(t) { s_deleterFunc(&t); }
}
};
// XDeleter.cpp
#include "Deleter.h"
template<>
DeleterFunc Deleter<I_x>::s_deleterFunc = FreeXInterface;
// YDeleter.cpp
#include "Deleter.h"
template<>
DeleterFunc Deleter<I_y>::s_deleterFunc = FreeYInterface;
对于您想要删除器的每种类型,您只需为专用 class 提供静态成员的实例化。调用Deleter<I_x>::operator()
的代码只需要包含Deleter.h
;链接器将负责将其与 XDeleter.cpp
.
中声明的匹配
请注意,我使用的是模板化 classes,而不是模板化函数,只是因为它允许您使用函数指针。但是您可以改为做一些简单的事情:
// Deleter.h
template <class T>
invokeDeleter(T* t);
// XDeleter.cpp
#include "Deleter.h"
template<>
invokeDeleter<I_x>(I_x* x)
{
...
}
// YDeleter.cpp
#include "Deleter.h"
template<>
invokeDeleter<I_y>(I_y* y)
{
...
}
声明函数对象的全局实例以便我可以在整个程序中导入和使用实例作为可调用对象的最佳方法是什么?
具体来说,我创建了一个模板 class,用作共享指针的自定义删除器。需要使用引用指针的 "Free" 函数删除第三方库中的几种指针类型。 class 的实例使用要删除的指针的类型以及指向具有 Free 函数签名的函数的指针进行实例化。我将实例声明为 const,因为成员函数指针不需要更改。
template <class T>
class Deleter {
public:
typedef typename bool(CALLING_CONVENTION *DeleterFunc)(T**);
Deleter(DeleterFunc deleter) : deleter_(deleter) {}
void operator() (T* t) { if (t) { deleter_(&t) }
private:
DeleterFunc deleter_;
};
static const Deleter<I_x> x_deleter(FreeXInterface);
我的第一次尝试是为 .h 文件中的每个指针类型创建实例,但是如果我在其他代码中包含此头文件,这会导致多重定义的符号。所以我将实例的声明更改为 "static" 并且这编译并且似乎工作正常,但我看到警告这不是一个好主意(特别是如果对象属于名称空间)因为静态导致链接为仅文件,每个编译单元都有自己的副本。
我的问题是,如果我真的不关心它们是否是文件之间的同一实例,这有关系吗?我没有将其用作全局数据,函数对象实际上没有任何状态。如果将这些对象声明为静态,我会对线程化有任何顾虑吗?有没有更好的方法来实现这个而不使用 static 关键字?
好吧,您的链接器问题的基本答案在这里:How do I use extern to share variables between source files?不过,让我们尝试做得更好一点:您目前每次实例化函数时都必须引用删除函数,而不是根据类型自动选择。
当然我们经常根据类型选择类型:std::vector<int>
是能够容纳int
的动态数组。那里的链接不是一个大问题:一切都或多或少是内联的,每个提到 std::vector<int>::push_back()
的翻译单元都有自己的目标代码副本,以将一个 int 放入一个 int 向量中,并且链接器(有时)提供帮助通过删除重复的实例化。但是这里我们想要一个对象,而不是类型。
那么模板和全局对象之间的中间点是什么?模板化 classes 的静态成员!检查一下:
// Deleter.h
typedef typename bool(CALLING_CONVENTION *DeleterFunc)(T**);
template <class T>
class Deleter {
public:
static DeleterFunc s_deleterFunc;
void operator() (T* t) {
if(t) { s_deleterFunc(&t); }
}
};
// XDeleter.cpp
#include "Deleter.h"
template<>
DeleterFunc Deleter<I_x>::s_deleterFunc = FreeXInterface;
// YDeleter.cpp
#include "Deleter.h"
template<>
DeleterFunc Deleter<I_y>::s_deleterFunc = FreeYInterface;
对于您想要删除器的每种类型,您只需为专用 class 提供静态成员的实例化。调用Deleter<I_x>::operator()
的代码只需要包含Deleter.h
;链接器将负责将其与 XDeleter.cpp
.
请注意,我使用的是模板化 classes,而不是模板化函数,只是因为它允许您使用函数指针。但是您可以改为做一些简单的事情:
// Deleter.h
template <class T>
invokeDeleter(T* t);
// XDeleter.cpp
#include "Deleter.h"
template<>
invokeDeleter<I_x>(I_x* x)
{
...
}
// YDeleter.cpp
#include "Deleter.h"
template<>
invokeDeleter<I_y>(I_y* y)
{
...
}