编译时抽象类处理中的clang与gcc



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

我有一个最简单的例子,它不能在少数版本的桌面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<abstract>::bar的无效返回类型而发出错误。


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

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

说明

在这种情况下,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();
}

最新更新