代码之家  ›  专栏  ›  技术社区  ›  SmacL

如何用C++模板减少编译时间

  •  32
  • SmacL  · 技术社区  · 16 年前

    this question

    5 回复  |  直到 9 年前
        1
  •  21
  •   UncleBens    16 年前

    我认为一般规则适用。尽量减少代码各部分之间的耦合。将太大的模板头拆分为一起使用的较小的函数组,这样就不必在每个源文件中都包含整个内容。

    另外,试着让头文件快速进入稳定状态,也许用一个较小的测试程序测试它们,这样当它们集成到一个较大的程序中时就不需要改变(太多)。

        2
  •  28
  •   Josh Kelley    11 年前

    • export keyword 理论上可以帮助,但是它的支持很差,在C++ 11中被正式删除。
    • 显式模板实例化(参见 here 或 here
    • Extern templates ,已被多个编译器作为扩展支持。我的理解是,extern模板不一定能让您将模板定义移出头文件,但它们确实可以加快编译和链接速度(通过减少模板代码必须实例化和链接的次数)。
    • 根据模板设计的不同,您可以将其大部分复杂性移到.cpp文件中。标准示例是一个类型安全向量模板类,它只包装一个类型不安全的向量 void* 无效* 驻留在.cpp文件中的向量。Scott Meyers在中给出了一个更详细的示例 有效C++ (第二版第42项,“谨慎使用私有继承权”)。
        3
  •  7
  •   Matthieu M.    12 年前

    首先,为了完整起见,我将介绍简单的解决方案:只在必要时使用模板化代码,并基于非模板代码(在其自己的源文件中实现)。

    举个例子:

    // "bigArray/bigArray.hpp"
    
    template <class T, class Allocator>
    class BigArray
    {
    public:
      size_t size() const;
    
      T& operator[](size_t index);
      T const& operator[](size_t index) const;
    
      T& at(size_t index);
      T const& at(size_t index);
    
    private:
      // impl
    };
    

    at

    // "bigArray/at.hpp"
    
    template <class Container>
    typename Container::reference_type at(Container& container,
                                          typename Container::size_type index)
    {
      if (index >= container.size()) throw std::out_of_range();
      return container[index];
    }
    
    template <class Container>
    typename Container::const_reference_type at(Container const& container,
                                                typename Container::size_type index)
    {
      if (index >= container.size()) throw std::out_of_range();
      return container[index];
    }
    

    好的,这会稍微改变调用:

    // From
    myArray.at(i).method();
    
    // To
    at(myArray,i).method();
    

    这个例子是虚构的,但总的观点是正确的。注意,由于它的通用性 at.hpp 不必包括 bigArray.hpp 并且仍然会产生像成员方法一样紧凑的代码,只是如果我们愿意,我们可以在其他容器上调用它。

    现在,一个 BigArray 水电站 如果她不使用它。。。因此,如果您更改文件中的代码,就可以减少她的依赖性,并且不会受到影响:例如alter std::out_of_range 调用以显示文件名和行号、容器的地址、大小以及我们尝试访问的索引。

    另一个(不太明显的)优点是,如果有完整性约束的话 那就违反了 在 显然是不合理的,因为它不能扰乱类的内部结构,从而减少了嫌疑犯的数量。

    C++ Coding Standards :

    第44条:喜欢写非成员非友函数

    广泛应用于工业生产中 促进

    当然,你只需要包括你所做的事情,应该有静态C++代码分析器来报告包含但未使用的头文件,这可以帮助解决这个问题。

        4
  •  6
  •   Stephen    16 年前
    • 你可以得到一个支持 export

    • 你可以用 explicit instantiation 但不幸的是,这要求您提前预测将要使用的模板类型。

    • 如果你能从你的算法中找出模板类型,你可以把它放在它自己的.cc文件中。

    • 我不建议这样做,除非这是个大问题,但是:您可以提供一个模板容器接口,该接口通过调用 void* 您可以随意更改的实现。

        5
  •  4
  •   Machavity Labib Hussain    6 年前

    使用模板作为问题解决技术可能会导致编译速度减慢。一个典型的例子是C中的std::sort vs.qsort函数。这个函数的C++版本需要编译的时间更长,因为它需要在每个翻译单元中解析,因为几乎每个函数都使用这个模板创建不同的实例(假设通常将封闭类型作为排序谓词提供)。

    尽管这些慢化是意料之中的,但是有一些规则可以帮助您编写高效的模板。其中四个描述如下。

    基尔的统治

    下面的C++特征/构造按编译顺序按降序排序:

    • 斯菲纳
    • 实例化函数模板
    • 调用别名
    • 向别名调用添加参数

    在设计和开发Boost.TMP时,使用了基于上述规则的优化。尽可能避免使用顶级构造进行快速模板编译。

    下面是一些示例,说明如何使用上面列出的规则。

    减少模板实例化

    让我们看看std::conditional。其声明如下:

    template< bool B, typename T, typename F >
    struct conditional;
    

    每当我们更改给定给该模板的三个参数中的任何一个时,编译器都必须为其创建一个新实例。例如,设想以下类型:

    struct first{};
    struct second{};
    

    现在,以下所有内容都将以不同类型的实例化结束:

    using type1 = conditional<true, first, second>;
    using type2 = conditional<true, second, first>;
    std::is_same_v<type1, type2>; // it’s false
    
    using type3 = conditional<false, first, second>;
    using type4 = conditional<false, second, first>;
    std::is_same_v<type1, type2>; // it’s false
    

    我们可以通过将conditional的实现更改为:

    template <bool>
    struct conditional{
         template <typename T, typename F>
         using type = T;
    };
    
    template <>
    struct conditional<false>{
         template <typename T, typename F>
         using type = F;
    };
    

    Odin Holmes' talk about the Kvasir library .

    创建显式模板实例化

    每当您怀疑模板的实例将经常被使用时,最好显式地实例化它。通常情况下, std::string std::basic_string<char> .

    为编译时算法创建专门化

    an example of this here . 在这个头文件中,排序算法是为255种类型的列表手动指定的。手动专门化加速了长列表的编译。

        6
  •  3
  •   AareP    16 年前