有模板方法但不公开实现

Have a template method but not expose implementation

我在TFRuntime.h

中有一个函数
class TFRuntime {
...
    template <typename T>
    Status computeXYSlice(Volume<T>* input, int zCoord, Volume<T> *output);
...
}

TFRuntime.cpp包括tensorflow库header如

#include <tensorflow/cc/ops/standard_ops.h>
#include <tensorflow/cc/saved_model/loader.h>

我不想将这些包含在 header 中,因为这会迫使任何使用 TFRuntime 的人也包含它们。但是,如果我希望 computeXYSlice 函数允许任何类型,我必须在 .h 文件中包含实现。然而,实现需要上述 tensorflow headers。

如何解决这个问题?我可以明确地 'instantiate' 只有 computeXYSlice 函数的某些变体吗?例如,Tfloatintdouble?或者有更好的方法吗?

Could I explicitly 'instantiate' only certain variants of the computeXYSlice function? E.g., where T is float or int or double?

你可以,它们的实现不需要在 header 中。稍后我会谈到这一点。但是如果你真的想允许任何类型那么你的模板必须是header。就是这样。

如果您希望只支持一小组类型,作为模板实例化,而不重载(有时在查找时可能会有所不同),标准有一个机制 显式模板实例化.

您的 header 看起来像这样...

class TFRuntime {
public:
    template <typename T>
    Status computeXYSlice(Volume<T>* input, int zCoord, Volume<T> *output);
};

...您的实现文件将包含显式实例 定义,就像这样...

template <typename T>
Status TFRuntime::computeXYSlice(Volume<T>* input, int zCoord, Volume<T> *output) {
  // Implement it
}

template
Status TFRuntime::computeXYSlice(Volume<int>*, int, Volume<int>*);

template
Status TFRuntime::computeXYSlice(Volume<double>*, int, Volume<double>*);

您必须包含显式实例化定义,否则您的程序是 ill-formed,不需要诊断。 The template function must be defined when implicit instantiation occurs, unless an explicit instantiation appears somewhere.

这有点麻烦。但是如果你的最终目标确实是有一堆实例化(而不是重载),那么你就是这样把它们联系在一起的。

我个人会继续使用 public 模板,当然,您将被迫将随附的 headers 与您自己的模板一起交付,但我会咬紧牙关在这种情况下,为 class.

的用户留下最大可能的灵活性

您至少可以将其隐藏在一个单独的“.inl”或“.impl”文件中(无法按照您要求的方式解决,但会使其不那么明显):

class TFRuntime
{
    template <typename T>
    Status computeXYSlice(Volume<T>* input, int zCoord, Volume<T>* output);
};

#include "TFRuntime.inl"

和:

#include <tensorflow/cc/ops/standard_ops.h>
#include <tensorflow/cc/saved_model/loader.h>

template <typename T>
Status TFRuntime::computeXYSlice(Volume<T>* input, int zCoord, Volume<T>* output)
{
    // ...
}

如果你真的想限制可用数据类型的范围,我会通过重载来实现:

class TFRuntime
{
public:
    Status computeXYSlice(Volume<int>* input, int zCoord, Volume<int>* output);
    Status computeXYSlice(Volume<double>* input, int zCoord, Volume<double>* output);
    Status computeXYSlice(Volume<unsigned long>* input, int zCoord, Volume<unsigned long>* output);
private:
    template <typename T>
    Status computeXYSlice(Volume<T>* input, int zCoord, Volume<T>* output);
};

因为现在模板函数是私有的,不能从 "outside" 调用它,您可以在 .cpp 文件中安全地实现它(其中只实例化所需的特化),连同正常调用模板函数的重载函数(您需要显式提供模板参数以防止递归——或者为模板函数指定一个不同的名称)。 不要实现已经在class定义中的重载,否则它们会被内联并且您再次将模板函数暴露给其他classes,要求实现可用再次...

您可以将使用过的(非模板化的)Tensorflow 功能包装在您自己的 header/sources 文件中,并从您的模板化代码中调用您的包装器:

// wrapper.h:
void some_function();

// wrapper.cpp:
#include <tensorflow/...>
void some_function() { /* use tensorflow stuff here */ }

// TFRuntime.h:
#include "wrapper.h" // no inclusion of Tensorflow headers involved

template <typename T>
void some_templated_function() { 
    some_function();
}

现场演示:https://wandbox.org/permlink/dWRT0AEi8alylTQB

但是,此解决方案增加了代码冗余,如果 Tensorflow API 发生更改,可能会停止工作。