2015-03-18 14 views
0

У меня есть следующий шаблон с внутренними классами в map.hpp файле:Правильный способ реализации оператора = для шаблонов вне класса как свободная функция

template<typename Key_T, typename Mapped_T> 
class Map { 
    // public members of Map ... 

    class Iterator { 
     //public members of Iterator ... 

     friend bool operator!=(const Iterator &i, const Iterator &j) { 
      return (i.link != j.link); 
     } 

     // private members of iterator ... 
     Node * link; 
    }; 
}; 
#include "map.hxx" //implementation file for member methods is separate 

В main.cpp я зову следующий и до сих пор все работает отлично:

Map<int, int> x; 
// bunch of insertions ... 
for (auto it = x.begin; it != x.end(); ++it) { 
    // Do something with it ... 
} 

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

В: Можно ли переместить свободную функцию в файл .hxx и как?

Я устал объявить функцию как друга в классе итератора и сделал следующее в файле реализации:

template<typename Key_T, typename Mapped_T> 
bool operator!=(const typename Map<Key_T, Mapped_T>::Iterator & i, 
       const typename Map<Key_T, Mapped_T>::Iterator & j) { 
    return (i.link != j.link); 
} 

Однако он не смог с:

$clang++ -std=c++11 -stdlib=libc++ -Wall -Wextra -g main.cpp 

Undefined symbols for architecture x86_64: 
    "shiraz::operator!=(shiraz::Map<int, int>::Iterator const&, shiraz::Map<int, int>::Iterator const&)", referenced from: 
     _main in main-3oCRAm.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Спасибо!

+0

Возможный дубликат: http://stackoverflow.com/q/495021/596781 –

+0

Почему вы спрашиваете о «синтаксисе», если у вас есть * линкер * ошибка? –

+0

Это может быть дубликат [этого вопроса] (http://stackoverflow.com/a/29062048/420683). Пожалуйста, покажите нам свою декларацию друга. – dyp

ответ

2

Объявление friend без соответствующего соответствия введет новую функцию в пространство имен. Эта функция может быть найдена только через ADL

Самый простой способ сделать то, что вы хотите, это оставить реализацию заглушки в классе iterator и передать ее на «реальную» функцию снаружи. Это сохраняет хороший ADL-поиск !=, который легко решает проблемы с большим количеством перегрузок. Вспомогательная функция может быть просто template<class Iterator> и быть более дружелюбной и иметь узкую реализацию и не быть найдена через ADL, а с полным контролем. Или это может быть статическая функция-член окружной карты.

template<typename Key_T, typename Mapped_T> 
class Map { 
    class Iterator; 
    static bool it_equal(Iterator const&, Iterator const&); 
    class Iterator { 
    friend class Map; 
    friend bool operator!=(const Iterator &i, const Iterator &j) { 
     return !Map::it_equal(i,j); 
    } 
    friend bool operator==(const Iterator &i, const Iterator &j) { 
     return Map::it_equal(i,j); 
    } 
    Node * link; 
    }; 
}; 

теперь ваш .hxx просто реализует bool Map<blah>::it_equal(blah), и вы сделали.

+0

Интересно, должен ли быть ответ на этот вопрос. – dyp

+0

@dyp Mayhap. Кстати, в то время как ваш ответ в другом вопросе хорош, он не совсем применим к операторам. Создание бесплатного шаблона оператор! = (T lhs, T rhs) 'очень невежлив, даже если вы специализируетесь только на нескольких типах. И не выведенный контекст делает сложно и для подтипа делать этот трюк, потому что пока '! =' будет найден, он не сможет вывести аргументы! (Я не проверял эти убеждения) – Yakk

+0

Hm. Я решил в своем ответе объяснить проблему и предложить * различные * решения. Я согласен, что большинство из них не будут хороши для вложенного типа. Не совсем понимаю вопрос, который вы упомянули по подтипам. – dyp