Специализация шаблона функции в другом классе / пространстве имен? - PullRequest
5 голосов
/ 18 января 2012

ПРИМЕЧАНИЕ. Этот вопрос только слабо связан с tinyxml, однако включение таких деталей может помочь лучше проиллюстрировать концепцию.

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

Часть «извлечение значения» также записывается в виде шаблона функции:

т.е.

template <typename Type>
Type getXmlCollectionItem(
    const char* elementName, TiXmlNode* child, TiXmlNode* parent);

Существуют специализации для поисковой части, для возврата различных типов значений дочерних элементов, например, std :: string и другие пользовательские объекты.

т.е.

template <>
std::string getXmlCollectionItem<std::string>(
    const char* elementName, TiXmlNode* child, TiXmlNode* parent);

template <>
MyObject getXmlCollectionItem<MyObject>(
    const char* elementName, TiXmlNode* child, TiXmlNode* parent);

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

Вопрос: Можно ли объявить шаблон функции в одном пространстве имен, например, namespace UtilityFunctions, который не имеет каких-либо знаний о конкретных типах объектов, таких как 'MyObject', а затем объявляет и определяет специализации этого шаблона функции в других пространствах имен, которые имеют знания о конкретных типах объектов, таких как 'MyObject'?

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

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

Ответы [ 2 ]

5 голосов
/ 18 января 2012

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

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

Итак, вот что вы не можете сделать:

namespace A { namespace B {
  template <typename T> int foo(T) {throw 1;}
}}

template <> int A::B::foo(int) {throw 0;}

Вы можете увидеть хорошее сообщение об ошибке для вышеупомянутого в http://www.comeaucomputing.com/tryitout/

"ComeauTest.c", line 5: error: the initial explicit specialization of function
          "A::B::foo(T) [with T=int]" must be declared in the namespace
          containing the template
  template <> int A::B::foo(int) {throw 0;} 
                        ^

Вот что вы можете сделать:

namespace A { namespace B {
  template <typename T> int foo(T) {throw 1;}
}}

namespace A { namespace B {
  template <> int foo(int) {throw 0;}
}}

Есть ли какая-то причина, по которой это может быть проблемой?

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

Вот пример:

namespace A { namespace B {
  template <typename T> int bar(T t) {return 0;}
  template <typename T> int foo(T t) {return bar(t);}
}}

namespace C {
  struct Bah {};
  int bar(Bah&) {return 1;}
}


int main(int argc,char** argv) 
{
  C::Bah bah;

  std::cout << A::B::foo(0) << std::endl;
  std::cout << A::B::foo(bah) << std::endl;
}

Отредактировано , чтобы добавить пример

1 голос
/ 18 января 2012

Смысл в следующем: «Каждое объявление для шаблона должно быть помещено в одно и то же пространство имен, как и повторные объявления любого другого именованного объекта» *

объявление / определение его в другом пространстве имен недопустимо, для получения дополнительной информации, пожалуйста, пройдите 12-й пункт в FAQ

...