如何避免每次编译项目时都重新编译特定的模板函数?[复制]

How can I avoid recompiling a specific template function each time I compile my project? [duplicate]

提问人:SirVivor 提问时间:5/22/2023 最后编辑:SirVivor 更新时间:5/22/2023 访问量:89

问:

假设我有一个带有模板的文件foo.hpp

template<int a>
void foo()
{
    // Complex function
}

我在我的:main.cpp

#include "foo.hpp"

int main()
{
    // quickly compiled code
    // ...

    foo<3>();

    // more quickly compiled code
}

现在每次我修改后编译我的项目,都需要重新编译,即使它没有改变。 在我的情况下,绝大多数编译时间都花在了编译上,因此避免这种情况至关重要。main.cppfoo<3>()foo<3>()

我想分两步编译我的项目:

  1. 编译。这需要很长时间,但我只做一次。foo<3>()
  2. 编译。这现在很快,因为已经编译好了。main.cppfoo<3>()

如何实现此行为?我尝试在不同的文件中进行显式实例化并首先编译它,但仍然需要相同的时间来编译。main.cpp

感谢您的帮助!

编辑: 澄清了我使用显式实例化尝试的内容:

创建一个新文件 :precompiled.cpp

#include "foo.hpp"

template void foo<3>();

然后尝试先用编译,然后使用 . 但这在第 2 步中再次实例化,我想避免这种情况。g++ -c precompiled.cppmain.cppg++ precompiled.o main.cppfoo<3>()

C++ 模板 显式实例化

评论

0赞 463035818_is_not_an_ai 5/22/2023
当您尝试在其他文件中显式实例化时,您到底做了什么?
0赞 463035818_is_not_an_ai 5/22/2023
坦率地说,我不确定我是否理解这个问题。如果它始终是但从不,则无需在 中实例化模板。只需致电 .如果是不同的数字,则需要重新编译foo<3>foo<42>mainfoo()
0赞 SirVivor 5/22/2023
澄清一下:我有一些,我编译了。然后我更改了上面的行,所以需要再次编译。这也是我想避免再次编译的地方。mainfoo<3>()mainfoo<3>()

答:

2赞 jett8998 5/22/2023 #1

如果使用函数,则无法避免实例化。请改用以下方法:foo<3>

template<int a>
struct foo
{
    void operator()() {
        //complex code here
    }
};

使用以下代码使文件命名为bar.hpp

#include "foo.hpp"
struct foo_3 {
    static foo<3> fooinst = foo<3>();
    void operator()() {
        foo_3::fooinst();
    }
};

然后使用(允许你预编译它返回一个文件。虽然我很困惑你为什么坚持使用模板。bar.hpp.gch

3赞 deribaucourt 5/22/2023 #2

模板需要在标头 () 中定义,并在编译单元 () 中实例化。与常规类不同,您不能在标头中声明函数并在编译单元中定义它,这将导致您期望的编译行为:仅在函数的实例化更改时重新编译函数。.hpp.cpp

我建议将对模板的所有调用包装在一个单独的文件中,并将这些调用包装在将从中调用的函数中。这样,您就可以在不重新编译的情况下修改 .但是,如果您更改在另一个单元中的使用方式,则将重新编译。.cppmain.cppmain.cppfoofoo

例::foo3.cpp

#include "foo.hpp"

void foo3() {
    foo<3>();
}

foo3.hpp:

#pragma once

void foo3();

main.cpp:

#include "foo3.hpp"

int main()
{
    // quickly compiled code
    // ...

    foo3();

    // more quickly compiled code
}
4赞 HolyBlackCat 5/22/2023 #3

标头中缺少 .extern template void foo<3>();foo

评论

0赞 Thomas Weller 5/22/2023
这很有趣。我以前从未在我们的代码中看到过这一点。这个“伎俩”有名字吗?它是常用的吗?是肮脏的黑客还是“干净的代码”?
2赞 HolyBlackCat 5/22/2023
@ThomasWeller 这是显式实例化声明,而不是显式实例化定义(这是一回事,但没有 ,除此之外,还必须在 .cpp 文件中使用,就像 OP 已经这样做一样)。我还没有看到有人称其为黑客。您可以使用它来缩短构建时间(正如 OP 想要的那样)或公开共享库中的模板。extern