有模板方法但不公开实现

时间:2018-06-28 09:17:28

标签: c++ templates header-files

我在TFRuntime.h中有一个函数

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

TFRuntime.cpp包含诸如tensorflow库头

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

我不想在标头中包含这些内容,因为这将迫使使用TFRuntime的任何人也将它们包含在内。但是,如果我希望computeXYSlice函数允许任何类型,则必须在.h文件中包括实现。但是该实现需要上面提到的张量流头。

如何解决这个问题?我是否可以仅“实例化” computeXYSlice函数的某些变体?例如,Tfloat还是intdouble?还是有更好的方法?

3 个答案:

答案 0 :(得分:5)

  

我可以只显式地“实例化” computeXYSlice函数的某些变体吗?例如,其中T为float或int或double?

您可以,并且它们的实现不必在标头中。一会儿,我会解决的。但是,如果您确实要允许任何类型,则您的模板必须位于标头中。就是这样。

如果您只希望支持一小部分类型(如模板实例化)而又不过载(有时在查找时可能有所作为),则该标准具有显式模板实例化的机制。< / p>

您的标题看起来像这样...

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

...并且您的实现文件将包含显式实例化 definitions ,就像这样...

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>*);

您必须包括显式的实例化定义,否则您的程序格式错误,不需要诊断。 The template function must be defined when implicit instantiation occurs, unless an explicit instantiation appears somewhere

这有点麻烦。但是,如果您的最终目标是确实有很多实例化(而不是重载),那么这就是将它们捆绑在一起的方式。

答案 1 :(得分:3)

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

// 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发生更改,可能会停止工作。

答案 2 :(得分:2)

我个人将只使用公共模板,当然,您将被迫随后将随附的标头与您自己的标头一起提供,但在这种情况下,我只是简单地说一下,以为用户提供最大的灵活性班上的。

您至少可以将其隐藏在单独的“ .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);
};

由于现在模板函数是私有的,因此不能从“外部”调用它,您可以在.cpp文件中安全地实现它(仅实例化所需的特殊化),而普通的重载函数则可以调用模板函数(您需要显式提供template参数以防止递归–或为模板函数指定其他名称)。 不要在类定义中实现已经实现的重载,否则它们将被内联,并且您将模板函数再次公开给其他类,要求实现再次可用...