Как скрыть шаблон помощника реализации? - PullRequest
18 голосов
/ 03 мая 2011

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

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

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

Ответы [ 5 ]

20 голосов
/ 03 мая 2011

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

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

4 голосов
/ 03 мая 2011

Два варианта на моей голове:

  1. Переместите всю реализацию в hpp-файл, который вы включаете внизу вашего h-файла.
  2. Измените код какшаблоны классов, а затем сделайте помощников личными.
3 голосов
/ 03 мая 2011

Установленный прецедент состоит в том, чтобы помещать подобные вещи в специально (то есть последовательно) именованное вложенное пространство имен. 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) {
        // ...
    }
};
3 голосов
/ 03 мая 2011

Поскольку пользователь вашего кода должен видеть полное определение функции 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
}
1 голос
/ 30 сентября 2015

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

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

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

#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's private
  Foo<int> foo_instance; //not allowed, because it's private
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...