c++ - 相同的代码由 clang 编译但在 gcc 中失败

标签 c++ gcc clang

是我错了还是编译器错了?我试图修复以在 gcc 下编译它,但找不到方法。错误消息非常简单明了 FactorialTree<T, 0>::print是私有(private)的,但为什么 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);
}

最佳答案

Clang 不应该编译它。 FactorialTree<T, 0>是一个特化,在其中你不确认对 operator<< 的友元.特化不与通用案例共享代码,因此您的 operator<<看不到特化的私有(private)领域。一种解决方案是制作 operator<<一个模板然后专门化它并使它成为两者的 friend 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);
  // ...
}

关于c++ - 相同的代码由 clang 编译但在 gcc 中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32445604/

相关文章:

c++ - undefined symbol ?

c++ - 读取由空格或换行符分隔的输入...?

c++ - 模板实例化——编译器如何避免重复符号?

c - 程序在 clang 中编译时有效,但在 Windows 中不是 gcc

c++ - 使用 IBPP 写入表时出错

c++ - 在等号左侧使用右值引用的规则是什么?

gcc - 在Fedora上使用Gold代替ld作为系统链接器

c - GCC 具有优化级别的堆栈保护功能

c - 多个 #ifndef 语句 - 应用哪一个

c++ - 我的 lambda 参数真的影响了我的本地人吗?