【问题标题】:Why do compiler options impact selection of template implementation?为什么编译器选项会影响模板实现的选择?
【发布时间】:2019-07-03 13:33:39
【问题描述】:

根据我是使用 -O3 编译还是未优化编译,编译器不会选择相同的函数模板实例化。使用 gcc (Debian 8.3.0-6) 8.3.0。

由于疏忽,我在函数模板声明中有一个默认实现:

#pragma once

#include <iostream>

template <int>
void func() { std::cerr << "default impl\n"; } // normally no impl here

以及他们的专长:

#include "func.h"

template <>
void func<1>()
{
    std::cerr << "special 1\n";
}

template <>
void func<2>()
{
    std::cerr << "special 2\n";
}

还有主要功能。

#include "func.h"

int main(void)
{
    func<1>();
    func<2>();

    return 0;
}

编译和运行g++ -Wall func.cpp main.cpp -o main &amp;&amp; ./main 给出:

special 1
special 2

使用优化 g++ -O3 -Wall func.cpp main.cpp -o main &amp;&amp; ./main 给出:

default impl
default impl

这是预期的吗?代码是否触发了我不知道的意外行为?

感谢制作Wandbox 的cmets 的@NathanOliver。编译有或没有优化显示不同的输出。

【问题讨论】:

  • 专业化定义在哪里?
  • 您能否将您的代码 sn-ps 替换为 minimal reproducible example,作为可以复制、粘贴和编译而无需将它们拼接在一起的单段代码?
  • @BiagioFesta 这可能是因为您的示例不等效,您的示例中没有输出,因此编译器优化了所有内容
  • @eerorika 专业化在 func.cpp 中。
  • @StoryTeller 这是有趣的信息,因此它应该是问题的一部分。

标签: c++ templates g++


【解决方案1】:

您的代码格式错误,无需诊断。因此,不同优化级别的不同行为是可能的。

[temp.expl.spec]

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

函数模板专门用于一个 TU,但另一个没有可用的专门化声明。激进的优化器很可能会选择隐式实例化(内联可用),而不是找到您在其他地方创建的实例化。解决方案是在标题中声明您的专业化存在。

【讨论】:

    【解决方案2】:

    由于 ODR 问题,您的行为未定义。

    ODR 表示每个符号应该只有一个定义。内联和模板函数可以有多个定义,但必须具有相同的实现,逐个标记。如果违反此规则,则无需诊断。

    编译您的示例时,编译器将实例化您的函数。看看这个:

    template <int>
    void func() { std::cerr << "default impl\n"; } // normally no impl here
    
    int main(void)
    {
        func<1>();
        func<2>();
    
        return 0;
    }
    

    这是编译器看到的。它看不到其他 cpp 文件。编译器将实例化模板并为您的函数创建附加定义。

    那么您的其他 cpp 文件将提供另一个不同的定义。

    解决方案是在您的标头中转发声明特化:

    template<> void func<1>();
    template<> void func<2>();
    

    这将告诉编译器特化是在别处声明的,而不是实例化默认的。

    【讨论】:

    • 如果我离开模板函数声明而没有实现(真正的错误)而没有前向声明特化,这是否仍然违反了什么?这样,当未提供专业化时,我的库将产生链接错误。
    • 好吧,如果你的前向声明没有提供定义,你会得到链接错误,如果这是你的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 2018-03-30
    • 1970-01-01
    • 2016-04-29
    • 2012-03-02
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多