【问题标题】:gcc inline the generic template function with a specialized definitiongcc 内联具有专门定义的通用模板函数
【发布时间】:2017-05-03 02:22:37
【问题描述】:

我怀疑 gcc 4.8.3 是否内联了不正确的模板函数...这个问题在调试模式下不会出现,而只会在优化模式下出现。但是,这发生在复杂的代码库中,我无法在简单的测试用例中重现该问题。

我的代码如下

#include "stdio.h"

class A {
 public:

    template<typename T> int WriteNative(const T) { 
      printf("here?\n")
      return 0; 
    }

    template<typename D> 
        void doit() {
        if (WriteNative<double>(1)) {
            printf("A\n");
        } else {
            printf("B\n");
        }
    }

};

// in my real code, this definition is in a different cpp file
template<> int A::WriteNative<double>(const double) { 
  return 1; 
}

int main() {
    A a;
    a.doit<float>();
}

在调试版本中,它会打印出 A,而在优化版本中,它会在此处打印出来?\nB

我猜任何内联器都使用通用模板函数定义,但不是专用的。但是 attribute ((noinline)) 没有帮助。

如果我的代码具有已定义的 C++ 行为,有人吗?以及如何解决这个问题?

【问题讨论】:

标签: c++ templates gcc inline compiler-optimization


【解决方案1】:

您没有明确说明这一点,但我猜在您的实际代码中,您未能在 A 的 .h 文件中声明特化。因此,当A.h 包含在单独的编译单元中时,编译器不知道WriteNative() 的特殊性。添加专业化声明应该可以解决问题,而不必将定义包含在同一文件中(即,不必内联):

class A {
    public:
    template<typename T> int WriteNative(const T) { 
      printf("here?\n")
      return 0; 
    }

    template<typename D> 
        void doit() {
        if (WriteNative<double>(1)) {
            printf("A\n");
        } else {
            printf("B\n");
        }
    }
};
template<> int A::WriteNative(const double);

您可以使用三个文件A.hA.cppmain.cpp 来重现您的问题,其中A.cpp 包含专业化的定义,因此当main.cpp 包含A.h 时,它是不知道的在优化期间发生内联时的特化,当使用-O0 编译时,不会发生内联,因此WriteNative()A.cpp 中的定义相关联。

编辑: 请参阅此 answer 引用规范来解释为什么这是正确的行为。

14.7.3 [temp.expl.spec]:

6/ 如果模板、成员模板或类模板的成员是 显式特化,则应声明该特化 在第一次使用会导致 隐式实例化发生在每个翻译单元中 发生这种使用;不需要诊断。如果程序 没有提供明确专业化的定义,并且 要么专业化的使用方式会导致 要发生的隐式实例化或成员是虚拟成员 函数,程序格式错误,不需要诊断。一个 永远不会为显式生成隐式实例化 已声明但未定义的特化。

【讨论】:

  • 是否在 C++ 请求的头文件中声明特化?
  • 不是。但是其他编译单元显然不会看到它。这是编译期间发生的事情以及链接期间发生的事情
  • @n.caillou 如果不需要,优化对我来说似乎过于激进。我认为编译器优化不应该改变代码的工作方式,除非我的原始代码没有声明是未定义的。
  • 但是您的编译器在编译main.o 时并不知道存在A.cpp 文件。您否认了整个按单元的编译过程。
  • 我同意这个假设,可以优化更多的代码。但是我认为这也类似于优化“bool b; b = false; if (b) ...”,其中 b 是全局的。编译器不会将 b 替换为 false,因为其他文件可以“extern b”并将其他值分配给“b”。这与函数模板专业化有何不同?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多