【问题标题】:clang vs gcc in abstract class handling in compile time编译时抽象类处理中的clang vs gcc
【发布时间】:2016-11-05 20:37:46
【问题描述】:

其中一个issues 的 nlohmann/json 开源库引起了我的注意。

我对@9​​87654322@ 在几个版本的桌面 gcc(4.8、4.9,也尝试过 5+)下的情况进行了最小的复制,但可以很好地与 mac clang 和 Android ndk 的 gcc 4.9 一起编译

#include <limits>

struct base {
    virtual void foo() = 0;
};

int main() {
    (void)numeric_limits<base>::is_signed;
}

GCC 正在尝试使用基类而不是派生类来实例化 std::numeric_limits

/usr/include/c++/4.8/limits: In instantiation of 'struct std::numeric_limits<base>': main.cpp:11:94:   required from here
/usr/include/c++/4.8/limits:309:7: error: cannot allocate an object of abstract type 'base'
min() _GLIBCXX_USE_NOEXCEPT { return _Tp(); }

我不太确定这是一个已知的编译器错误(如果失败)还是功能/宽松规则(如果成功)

我尝试使用 std::is_abstract 解决它,但它没有帮助,看起来 enable_if 中没有发生“短路”评估并且错误保持不变

我的问题主要不是如何为 gcc 解决这个问题,而是天气这是编译器错误或代码错误


编辑:添加了“更小”的示例,没有任何标准库依赖:

template <typename T>
struct foo
{
  static T bar();
  static constexpr bool value = true;
};

struct abstract
{
  virtual ~abstract() = 0;
};

int main()
{
  (void) foo<abstract>::value;
}

在 clang 3.9.0 上编译,但 gcc 7 快照针对 foo&lt;abstract&gt;::bar 的无效返回类型发出错误。


Edit2:我有点惊讶我最初的问题未经我同意就被编辑了,我不知道 SO 允许这样做 :) 感谢您的帮助,尽管我认为它带来了一些混乱和错误的答案,主要是因为文本和代码不再连接

【问题讨论】:

  • 问题错了,你用过std::numeric_limits&lt;base&gt;,为什么会是std::numeric_limits&lt;derived&gt;
  • @ShmuelH。继承是一条红鲱鱼,我从示例中删除了derived
  • 对不起,这不是我的问题,是有人编辑的,让我很吃惊:)
  • @OlegBogdanov 这不是我的编辑,但正如预期的那样,两个编译器都使用基类实例化。这不是编译器之间存在差异的原因。
  • @Oktalist 我现在完全清楚了,谢谢,只是编辑给一些回答者带来了困惑,恕我直言

标签: c++ gcc clang abstract-class


【解决方案1】:

,这不是错误。这只是一个糟糕的测试。

说明

GCCclang 在这种情况下的唯一区别是它们处理模板类函数的方式:

  • GCC: 一次全部搞定。
  • clang:只有用过的那个。

在我们的第一个示例中,函数min() 没有被调用,因此clang 没有问题。 GCC,解析所有函数,发现min()无效。

在第二个例子中,同样的情况发生了:bar() 不会被任何人调用,因此clang 可以接受它的格式错误。但同样,GCC 有问题,虽然在程序的任何地方都没有使用过。

很好的测试

仅仅说有问题是不够的,让我们来解决它:这个例子会失败,GCCclang 都会出现几乎相同的错误(invalid abstract return type ‘base’allocating an object of abstract class type 'base')。

#include <limits>

struct base {
    virtual void foo() = 0;
};

int main() {
    (void)std::numeric_limits<base>::min();
}

【讨论】:

  • 不,测试很好,程序在两个编译器中都应该失败。 numeric_limits&lt;base&gt; 应该实例化类的所有成员函数的声明,导致 base 被用作抽象返回类型,这是格式错误的。
  • @0x499602D2 在语言律师的世界里,你是对的。但是如果一个函数不被使用,生成它会浪费资源。
  • Clang 正确拒绝了template &lt;typename T&gt; struct X { int f(T); }; X&lt;void&gt;{};
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-15
  • 2014-11-02
  • 2019-08-25
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多