2015-09-07 2 views
0

Является ли это я или компилятор неправильным? Я попытался исправить это, скомпилированное под gcc, но не смог найти способ. Сообщение об ошибке довольно просто, что FactorialTree<T, 0>::print является закрытым, но тогда почему clang принимает его без проблем? Кроме того, как я могу исправить это для gcc?Тот же код компилируется clang, но не работает в gcc

#include <ostream> 
#include <cstring> 

template<typename T, std::size_t nChildren> 
class FactorialTreeBase 
{ 
protected: 
    FactorialTreeBase<T, nChildren + 1> *parent; 

public: 
    T data; 

    FactorialTreeBase(FactorialTreeBase<T, nChildren + 1> *p, const T &t) 
    : parent(p) 
    , data(t) 
    { 
    } 

    const FactorialTreeBase<T, nChildren + 1> *getParent() const 
    { 
    return parent; 
    } 

    FactorialTreeBase<T, nChildren + 1> *getParent() 
    { 
    return parent; 
    } 

protected: 
    static void printIndents(std::ostream &os, std::size_t nIndents) 
    { 
    for (std::size_t i = 0; i < nIndents; ++i) 
    { 
     os << " "; 
    } 
    os << "+-"; 
    } 
}; 

template<typename T, std::size_t nChildren> 
class FactorialTree 
: public FactorialTreeBase<T, nChildren> 
{ 
    friend class FactorialTree<T, nChildren + 1>; 

public: 
    FactorialTree<T, nChildren - 1> *children[nChildren]; 

    FactorialTree(FactorialTree<T, nChildren + 1> *p = nullptr, const T &t = T()) 
    : FactorialTreeBase<T, nChildren>(p, t) 
    { 
    std::memset(children, 0, nChildren * sizeof *children); 
    } 

    FactorialTree(const FactorialTree<T, nChildren> &) = delete; 
    FactorialTree<T, nChildren> &operator=(const FactorialTree<T, nChildren> &) = delete; 
    FactorialTree(FactorialTree<T, nChildren> &&) = delete; 
    FactorialTree<T, nChildren> &operator=(FactorialTree<T, nChildren> &&) = delete; 

    ~FactorialTree() 
    { 
    for (std::size_t i = 0; i < nChildren; ++i) 
    { 
     if (children[i]) 
     { 
     delete children[i]; 
     } 
    } 
    } 

    friend std::ostream &operator<<(std::ostream &os, const FactorialTree<T, nChildren> &ft) 
    { 
    for (std::size_t i = 0; i < nChildren; ++i) 
    { 
     if (ft.children[i]) 
     { 
     ft.children[i]->print(os, 0); 
     } 
    } 
    return os; 
    } 

private: 
    void print(std::ostream &os, std::size_t nIndents) const 
    { 
    this->printIndents(os, nIndents); 
    os << this->data << '\n'; 
    for (std::size_t i = 0; i < nChildren; ++i) 
    { 
     if (children[i]) 
     { 
     children[i]->print(os, nIndents + 1); 
     } 
    } 
    } 
}; 

template<typename T> 
class FactorialTree<T, 0> 
: public FactorialTreeBase<T, 0> 
{ 
    friend class FactorialTree<T, 1>; 

public: 
    FactorialTree(FactorialTree<T, 1> *p = nullptr, const T &t = T()) 
    : FactorialTreeBase<T, 0>(p, t) 
    { 
    } 

private: 
    void print(std::ostream &os, std::size_t nIndents) const 
    { 
    this->printIndents(os, nIndents); 
    os << this->data << '\n'; 
    } 
}; 

#include <iostream> 

enum 
{ 
    N = 3 
}; 

template<std::size_t n> 
void fillTree(FactorialTree<int, n> *ft) 
{ 
    for (std::size_t i = 0; i < n; ++i) 
    { 
    ft->children[i] = new FactorialTree<int, n - 1>; 
    ft->children[i]->data = i; 
    fillTree(ft->children[i]); 
    } 
} 

template<> 
void fillTree(FactorialTree<int, 0> *) 
{ 
} 

template<std::size_t n> 
void printAndCutTree(FactorialTree<int, n> *ft) 
{ 
    std::cout << *ft << '\n'; 
    for (std::size_t i = 1; i < n; ++i) 
    { 
    delete ft->children[i]; 
    ft->children[i] = nullptr; 
    } 
    printAndCutTree(ft->children[0]); 
} 

template<> 
void printAndCutTree(FactorialTree<int, 0> *) 
{ 
} 

int main() 
{ 
    FactorialTree<int, N> t; 
    fillTree(&t); 
    printAndCutTree(&t); 
} 
+3

Вы должны обрезать код вниз, он включает в себя много ненужных линий. –

ответ

3

Clang не должен был скомпилировать это. FactorialTree<T, 0> - это специализация, и в ней вы не подтверждаете дружбу для operator<<. Специализация не разделяет код с общим случаем, поэтому ваш operator<< не может видеть частные поля специализации. Одним из решений этой проблемы было бы сделать operator<< шаблон и затем, специализирующимся его и делает его друга в обоих FactorialTree<T, nChildren> и FactorialTree<T, 0>:

// forward declaration of the FactorialTree 
template<typename T, std::size_t nChildren> 
class FactorialTree; 

// operator<< is now a template, rather than an overload 
template<typename T, std::size_t nChildren> 
std::ostream &operator<<(std::ostream &os, const FactorialTree<T, nChildren> &ft) 
{ 
    for (std::size_t i = 0; i < nChildren; ++i) 
    { 
    if (ft.children[i]) 
    { 
     ft.children[i]->print(os, 0); 
    } 
    } 
    return os; 
} 

// the generic case 
template<typename T, std::size_t nChildren> 
class FactorialTree 
: public FactorialTreeBase<T, nChildren> 
{ 
    friend class FactorialTree<T, nChildren + 1>; 
    // specialising operator<< and making it a friend: 
    friend std::ostream &operator<< <>(std::ostream &os, const FactorialTree<T, nChildren+1> &ft); 
    // ... 
} 

// the specialisation 
template<typename T> 
class FactorialTree<T, 0> 
: public FactorialTreeBase<T, 0> 
{ 
    friend class FactorialTree<T, 1>; 
    // again, specialising operator<< and making it a friend 
    friend std::ostream &operator<< <>(std::ostream &os, const FactorialTree<T, 1> &ft); 
    // ... 
} 
+0

Ваше решение работает для GCC, но теперь терпит неудачу в звоном .. '/tmp/a-696a74.o: В функции \' аннулируются printAndCutTree <1u> (FactorialTree *) ':. a.cpp :(text._Z15printAndCutTreeILj1EEvP13FactorialTreeIiXT_EE [_Z15printAndCutTreeILj1EEvP13FactorialTreeIiXT_EE ] + 0x1d): неопределенная ссылка на \ 'operator << (std :: ostream &, FactorialTree const &) '' – xiver77

+0

Обновлен ответ, компилируется на clang 3.4 –

Смежные вопросы