2017-01-02 14 views
3

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

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

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

Но по некоторым причинам следующие три класса игрушек не будут компилироваться. В нем не говорится о доступе к частным членам. Что я делаю неправильно?

Файл main.cpp:

#include <iostream> 
#include "Node.h" 
#include "NodeImpl.h" 

int main(int argc, char** args) { 
    Node<int> n("Test", 2); 
    std::cout << getName(n) << std::endl; 
} 

Файл Node.h:

#pragma once 
#include <string> 

template<typename T> 
class NodeImpl; 

template<typename T> 
class Node { 
public: 
    typedef T value_type; 
    Node(const std::string& name, const T& value) : name(name), value(value) {} 

private: 
    std::string name; 
    T value; 
    friend class NodeImpl<T>; 
}; 

Файл NodeImpl.h:

#pragma once 
#include "Node.h" 

template<typename T> 
std::string getName(Node<T>& n); 

template<typename T> 
class NodeImpl { 
    NodeImpl(Node<T>& node) : mNode(node) { 
    } 
    Node<T>& mNode; 

    std::string name() { 
     return mNode.name; 
    } 

    friend std::string getName(Node<T>& n); 
}; 

template<typename T> 
std::string getName(Node<T>& n) { 
    auto x = NodeImpl<T>(n); 
    return x.name(); 
} 
+5

Друзья ваших друзей не ваши друзья – Danh

+0

Спасибо за помощь. Конечно, декларация друзей не является транзитивной. Я изменил 'NodeImpl.h'. Мысль это было решением. Но все же он не компилируется. :-( – Aleph0

ответ

2

warning produced by GCC дает представление:

warning: friend declaration 'std::__cxx11::string getName(Node<T>&)' declares a non-template function [-Wnon-template-friend] 
friend std::string getName(Node<T>& n); 
            ^
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) 

Других слов, ваш класс NodeImpl<int> был подружился глобальная функция std::string getName(Node<int> &), которая не имеет отношение к функции std::string getName<int>(Node<int> &) реализованной из шаблона функции template <class T> std::string getName(Node<T> &) для T = int.

Так правильное решение заключается в следующем:

template<typename T> 
class NodeImpl { 
    // ... as before ... 

    friend std::string getName<T>(Node<T>& n); 
}; 

[live example] Это показывает, что это решение действительно работает.

+0

Это потрясающе. Я использую Visual Studio. Большое спасибо. :-) – Aleph0