【问题标题】:When does gcc compile unused template code?gcc 什么时候编译未使用的模板代码?
【发布时间】:2018-08-04 19:19:53
【问题描述】:

我有以下(诚然是人为的)代码,在 gcc 6 中编译得很好,但在 gcc 7 中不能编译。请注意在 bar 的定义中使用了未声明的构造函数。如果该函数曾在代码的其他地方被引用,这应该会打印一个错误(取消注释foo.bar() 会导致 gcc 6 打印一个错误)。但是,gcc 7 即使不使用该函数也会打印错误。

某些更改会导致代码也使用 gcc 7 进行编译(例如,如果 BA 的定义中被替换为 T),而某些更改会导致它无法使用 gcc 6 进行编译(例如,如果 @987654326 @ 未使用)。这里发生了什么? gcc 什么时候决定编译未使用的模板代码?不同版本的gcc使用不同的规则来决定吗?

struct B {};

template <typename T>
struct A {

    B* bar()
    {
        // undeclared constructor
        return new B(this->b);
    }

    B* b;
};

int main (int argc, char* argv[])
{
    A<int> foo;

    //foo.bar();
}

【问题讨论】:

  • “因为没有使用指针参数定义隐式复制构造函数,” - 如果是,它就不是复制构造函数。
  • 很公平。不知道还有什么可以调用这样一个组成的函数。
  • 它只是一个构造函数。
  • 抛出异常。打印编译错误。
  • 即使没有 A&lt;int&gt; 实例化,编译器也会拒绝你的代码,因为它可以证明无论 T,函数 bar 永远不会有效。但它不是必须的,它被添加是因为它被认为是有帮助的。

标签: c++ templates gcc copy-constructor


【解决方案1】:

也许我遗漏了一些东西,但您似乎正在尝试从 B 指针构造 B 对象。并且没有默认构造函数可以做到这一点。所以你肯定想要:

struct B {
    B( B * b ) {
    }
};

【讨论】:

  • 是的,但我的意思是,我很惊讶地发现即使没有此声明,旧版本的 gcc 也能正常编译,而 gcc 7 会抛出错误。
  • 嗯,旧版本的 GCC 比新版本有更多的错误,或者至少我们如此希望 - 我认为最新版本的代码对您的代码是正确的
  • 标准没有隐晦的更新。你的代码是否应该编译我真的没有资格说,但到底是什么,我会说“不”。
  • 标准中某处是否证实了这一点?
  • 我的标准拖网时代早已过去 - 但如果你真的想学习 C++,我可以推荐它。
【解决方案2】:

A::bar() 是模板类中的非模板成员函数。如果它本身是一个模板,那么 SFINAE 将允许在不调用 bar() 时编译代码。但是按照您现在的方式,一旦A 被一些模板参数实例化,所有这些都应该是有效的。

一种解决方案是:

template <typename T>
struct A {

    template <typename X>
    X* bar()
    {
        // static_assert(is_same<X, B>) if you want
        return new X(this->b);
    }

    B* b;
};

那么你会调用a.bar&lt;B&gt;()而不是a.bar(),如果你不调用它,它就不会被实例化,也不会导致错误。

【讨论】:

  • 但为什么它可以编译某些版本的 gcc 而不是其他版本?
  • @willpett:一般的 C++ 编译器和 GCC 特别倾向于接受大量技术上不完善的代码。随着时间的推移,这些“不是 C++ 但足够接近”的程序中的一些开始被较新的编译器拒绝,因为编译器获得了与优化相关的更强大的功能,或者更正式的更严格的内部机制。因此,虽然 GCC 6 接受您的代码没有错,但 GCC 7 拒绝它也没有错。 GCC 4 也接受了很多 GCC 6 拒绝的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 2022-01-12
  • 2015-07-25
  • 2014-09-09
相关资源
最近更新 更多