Иметь метод шаблона, но не выставлять реализацию - PullRequest
0 голосов
/ 28 июня 2018

У меня есть функция в TFRuntime.h

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

TFRuntime.cpp включает заголовки библиотеки тензорного потока, такие как

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

Я не хочу делать эти включения в заголовке, так как это заставит любого, кто использует TFRuntime, включать их. Однако, если я хочу, чтобы функция computeXYSlice позволяла использовать любой тип, я должен включить реализацию в файл .h. Однако для реализации требуются упомянутые выше заголовки тензорного потока.

Как мне обойти эту проблему? Могу ли я явно «создать экземпляр» только определенных вариантов функции computeXYSlice? Например, где T является float или int или double? Или есть лучший способ?

Ответы [ 3 ]

0 голосов
/ 28 июня 2018

Лично я бы остался с общедоступным шаблоном, конечно, вы будете вынуждены затем доставлять включенные заголовки вместе с вашими собственными, но в этом случае я бы просто обозначил байты, чтобы предоставить пользователям максимальную гибкость. вашего класса.

Вы можете скрыть это, по крайней мере, в отдельном файле ".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 (где будут создаваться только необходимые специализации) вместе с обычными перегруженными функциями, вызывающими функция шаблона (вам нужно явно указать параметр шаблона для предотвращения рекурсии - или дать функции шаблона другое имя). не реализуйте перегрузки уже в определении класса, в противном случае они становятся встроенными, и вы снова предоставляете функцию шаблона другим классам, требуя, чтобы реализация была снова доступна ...

0 голосов
/ 28 июня 2018

Вы можете обернуть использованную (не шаблонную) функциональность 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 будет изменен.

0 голосов
/ 28 июня 2018

Могу ли я явно «создать экземпляр» только определенных вариантов функции computeXYSlice? Например, где T является float или int или double?

Возможно, и их реализация не обязательно должна быть в шапке. Я вернусь к этому через минуту. Но если вы действительно хотите разрешить любой тип , тогда ваш шаблон должен быть в заголовке. Вот только как это.

Если вы хотите поддерживать только небольшой набор типов в качестве экземпляров шаблона без перегрузки (иногда это может иметь значение при поиске), в стандарте есть механизм для явного создания шаблона .

Ваш заголовок будет выглядеть примерно так ...

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

Вы должны включить явные определения экземпляров, в противном случае ваша программа некорректна, диагностика не требуется. Функция шаблона должна быть определена, когда происходит неявное создание экземпляра, если только где-то не появляется явное создание .

Это немного громоздко. Но если ваша конечная цель состоит в том, чтобы действительно иметь кучу экземпляров (в отличие от перегрузок), вот как вы все это связываете.

...