Как скрыть шаблон помощника реализации?

Предположим, что у меня есть две функции шаблона, объявленные в файле заголовка:

template <typename T> void func1(const T& value);
template <typename T> void func2(const T& value);

И предположим, что реализация этих функций (также в файле заголовка, а не в исходном файле, потому что они являются шаблонами) использует некоторую вспомогательную функцию реализации, которая также является шаблоном:

template <typename T> void helper(const T& value) {
    // ...
}

template <typename T> void func1(const T& value) {
    // ...
    helper(value);
}

template <typename T> void func2(const T& value) {
    // ...
    helper(value);
}

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

Ответы

Ответ 1

Общий подход (например, используемый во многих библиотеках Boost) заключается в том, чтобы помещать помощника в пространство имен, называемое details, возможно, в отдельном заголовке (включенном в заголовок "public" ).

Там нет способа предотвратить его видимость и вызываемость, но это довольно ясно указывает, что это часть реализации, а не интерфейс.

Ответ 2

Два варианта с головы:

  • Переместите всю реализацию в файл hpp, который вы укажете в нижней части h файла.
  • Обновите свой код как шаблоны классов, а затем сделайте помощников конфиденциальными.

Ответ 3

Поскольку пользователю вашего кода необходимо увидеть полное определение функции func1, его можно реализовать, а также реализовать реализацию вспомогательной функции.

Но если вы переместите реализацию в другой файл, пользователю придется столкнуться с объявлением шаблона:

//templates.h
template< typename T > void f1( T& );

#include <templates_impl.h> // post-inclusion

И определение:

// templates_impl.h
template< typename T > void f1_helper( T& ) {
}

template< typename T > void f1( T& ) {
   // the function body
}

Ответ 4

Установленный прецедент заключается в том, чтобы помещать подобную вещь в специально (то есть последовательно) с именем вложенное пространство имен. Boost использует namespace details, Loki использует namespace Private. Очевидно, ничто не может помешать кому-либо использовать содержимое этих пространств имен, но оба названия передают значение, что их содержимое не предназначено для общего потребления.

Говоря проще, можно превратить func1 и func2 из шаблонов свободных функций в статические шаблоны функций-членов некоторого общего класса; Таким образом, helper может просто быть частным членом указанного класса, невидимым для внешнего мира:

struct funcs {
    template<typename T>
    static void func1(T const& value) {
        // ...
        helper(value);
    }

    template<typename T>
    static void func2(T const& value) {
        // ...
        helper(value);
    }

private:
    template<typename T>
    static void helper(T const& value) {
        // ...
    }
};

Ответ 5

Я хотел бы (как было сказано ранее) создать класс шаблона, сделать все функции static и вспомогательную функцию приватной. Но кроме того, я бы также рекомендовал сделать конструктор закрытым, как показано ниже:

template <typename T>
class Foo{
public:
  static void func1(const T& value);
  static void func2(const T& value);
private:
  Foo();
  static void helper(const T& value);
}

Когда вы создадите конструктор private, компилятор не разрешит экземпляры этого класса шаблонов. Таким образом, следующий код станет незаконным:

#include "foo.h"

int main(){
  int number = 0;
  Foo<int>::func1(number); //allowed
  Foo<int>::func2(number); //allowed
  Foo<int>::helper(number); //not allowed, because it private
  Foo<int> foo_instance; //not allowed, because it private
}

Так зачем кому-то это хотеть? Потому что наличие разных экземпляров, которые ТОЧНО, то же самое, чего вы, вероятно, никогда не захотите. Когда компилятор сообщает вам, что конструктор какого-либо класса является приватным, вы можете предположить, что наличие разных экземпляров его было бы лишним.