Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 存储C++;.CPP文件中的模板函数定义_C++_Templates - Fatal编程技术网

C++ 存储C++;.CPP文件中的模板函数定义

C++ 存储C++;.CPP文件中的模板函数定义,c++,templates,C++,Templates,我有一些模板代码,我更愿意将其存储在CPP文件中,而不是内联在头文件中。我知道这是可以做到的,只要你知道哪些模板类型将被使用。例如: .h文件 class foo { public: template <typename T> void do(const T& t); }; template <typename T> void foo::do(const T& t) { // Do something with t } temp

我有一些模板代码,我更愿意将其存储在CPP文件中,而不是内联在头文件中。我知道这是可以做到的,只要你知道哪些模板类型将被使用。例如:

.h文件

class foo
{
public:
    template <typename T>
    void do(const T& t);
};
template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
class-foo
{
公众:
模板
无效do(常数T&T);
};
.cpp文件

class foo
{
public:
    template <typename T>
    void do(const T& t);
};
template <typename T>
void foo::do(const T& t)
{
    // Do something with t
}

template void foo::do<int>(const int&);
template void foo::do<std::string>(const std::string&);
模板
void foo::do(常量T&T)
{
//用t做点什么
}
模板void foo::do(const int&);
模板void foo::do(const std::string&);
注意最后两行-foo::do模板函数仅用于int和std::strings,因此这些定义意味着应用程序将链接


我的问题是——这是一个令人讨厌的黑客行为,还是会在其他编译器/链接器中起作用?我目前只在VS2008中使用这段代码,但希望移植到其他环境。

是的,这是进行专门化显式实例化的标准方法。如前所述,不能用其他类型实例化此模板


编辑:根据注释更正。

您描述的问题可以通过在标题中定义模板或通过您上面描述的方法来解决

我建议阅读以下几点:


他们详细讨论了这些(和其他)模板问题。

这应该可以在支持模板的任何地方正常工作。显式模板实例化是C++标准的一部分。

< P>在最新的标准中,有一个关键字(<代码>导出< /代码>)有助于减轻这个问题,但它不是在我知道的任何编译器中实现的,除了Cimo.


请参阅关于此的说明。

此代码格式正确。您只需注意模板的定义在实例化时是可见的。引用标准§14.7.2.4:

非导出函数模板、非导出成员函数模板或类模板的非导出成员函数或静态数据成员的定义应存在于明确实例化的每个翻译单元中


你所举的例子没有错。但我必须说,我认为在cpp文件中存储函数定义是没有效率的。我只理解需要将函数的声明和定义分开


当与显式类实例化一起使用时,Boost概念检查库(BCCL)可以帮助您在cpp文件中生成模板函数代码。

这绝对不是一个令人讨厌的黑客行为,但请注意,您必须这样做(显式模板专门化)对于要与给定模板一起使用的每个类/类型。在许多类型请求模板实例化的情况下,.cpp文件中可能有很多行。要解决此问题,可以在使用的每个项目中使用TemplateClassInst.cpp,以便更好地控制将实例化的类型。显然,这个解决方案并不完美(又名银弹),因为您可能最终会破坏ODR:)。

对于本页上想知道显式模板专业化(或至少在VS2008中)的正确语法是什么的其他人来说(正如我所做的),它如下所示

在您的.h文件中

模板
福班
{
公众:
空心钢筋(const T&T);
};
在您的.cpp文件中

template <class T>
void foo<T>::bar(const T &t)
{ }

// Explicit template instantiation
template class foo<int>;
模板
无效foo::bar(常数T&T)
{ }
//显式模板实例化
模板类foo;

更新时间到了!创建一个内联(.inl,或者任何其他)文件,并简单地复制其中的所有定义。确保在每个函数上方添加模板(
模板
)。现在,不在内联文件中包含头文件,而是执行相反的操作。在类声明之后包含内联文件(
#包含“file.inl”


我真的不知道为什么没有人提到这件事。我看不出有什么直接的缺点。

你的例子是正确的,但不是很好移植。 还可以使用稍微干净的语法(如@namespace sid等所指出的)

但是,假设模板类是要共享的某个库的一部分

是否应该编译模板类的其他版本

库维护人员是否应该预测类的所有可能模板化使用

另一种方法 在源代码中添加第三个文件,即模板实现/实例化文件

lib/foo.hpp
在库中/从库中

foo.MyType.cpp
使用库,显式模板实例化
foo

示例。cpp
可以引用本地声明,但也不会重新编译
foo

<>请注意,大多数编译器/ LTENS/代码助手不会检测到这是一个错误,因为没有根据C++标准的错误。
但是,当您将此翻译单元链接到一个完整的可执行文件时,链接器将找不到定义模板函数的标准方法
foo

的定义版本。我认为我读过三种定义模板的方法。或者可能是4。每个人都有自己的优点和缺点

  • 在类定义中定义。我一点也不喜欢这个,因为我认为类定义严格地仅供参考,应该易于阅读。然而,在类中定义模板比在类外定义模板要简单得多。而且并非所有的模板声明都具有相同的复杂性。此方法还使模板成为真正的模板

  • 在同一标头中定义模板,但在类之外。大多数时候,这是我喜欢的方式。它使您的类定义保持整洁,模板仍然是一个真正的模板。但是,它需要完整的模板命名,这可能很棘手。此外,所有人都可以使用您的代码。但是如果你需要你的代码内联,这是最好的
    // Consider adding "anti-guard" to make sure it's not included in other translation units
    #if __INCLUDE_LEVEL__
      #error "Don't include this file"
    #endif
    
    // Yes, we include the .cpp file
    #include <lib/foo.cpp>
    #include "MyType.hpp"
    
    template class foo<MyType>;
    
    #pragma once
    
    #include <lib/foo.hpp>
    #include "MyType.hpp"
    
    // Declare `temp`. Doesn't need to include `foo.cpp`
    extern foo<MyType> temp;
    
    #include "foo.MyType.hpp"
    
    MyType instance;
    
    // Define `temp`. Doesn't need to include `foo.cpp`
    foo<MyType> temp;
    
    void example_1() {
        // Use `temp`
        temp.bar(instance);
    }
    
    void example_2() {
        // Function local instance
        foo<MyType> temp2;
    
        // Use templated library function
        temp2.bar(instance);
    }
    
    #include <lib/foo.hpp>
    
    // Causes compilation errors at link time since we never had the explicit instantiation:
    // template class foo<int>;
    // GCC linker gives an error: "undefined reference to `foo<int>::bar()'"
    foo<int> nonExplicitlyInstantiatedTemplate;
    void linkerError()
    {
        nonExplicitlyInstantiatedTemplate.bar();
    }
    
    //test_template.h:
    #pragma once
    #include <cstdio>
    
    template <class T>
    class DemoT
    {
    public:
        void test()
        {
            printf("ok\n");
        }
    };
    
    template <>
    void DemoT<int>::test()
    {
        printf("int test (int)\n");
    }
    
    
    template <>
    void DemoT<bool>::test()
    {
        printf("int test (bool)\n");
    }
    
    error : multiple definition of `DemoT<int>::test()'; your.o: .../test_template.h:16: first defined here
    
    //test_template.h:
    #pragma once
    #include <cstdio>
    
    template <class T>
    class DemoT
    {
    public:
        void test()
        {
            printf("ok\n");
        }
    };
    
    template <>
    void DemoT<int>::test();
    
    template <>
    void DemoT<bool>::test();
    
    // Instantiate parametrized template classes, implementation resides on .cpp side.
    template class DemoT<bool>;
    template class DemoT<int>;
    
    //test_template.cpp:
    #include "test_template.h"
    
    template <>
    void DemoT<int>::test()
    {
        printf("int test (int)\n");
    }
    
    
    template <>
    void DemoT<bool>::test()
    {
        printf("int test (bool)\n");
    }
    
     error LNK2019: unresolved external symbol "public: void __cdecl DemoT<int>::test(void)" (?test@?$DemoT@H@@QEAAXXZ) referenced in function
    
    //test_template.h:
    #pragma once
    #include <cstdio>
    
    template <class T>
    class DemoT
    {
    public:
        void test()
        {
            printf("ok\n");
        }
    };
    
    #ifdef _WIN32
        #define DLL_EXPORT __declspec(dllexport) 
    #else
        #define DLL_EXPORT
    #endif
    
    template <>
    void DLL_EXPORT DemoT<int>::test();
    
    template <>
    void DLL_EXPORT DemoT<bool>::test();
    
    class Model
    {
        template <class T>
        void build(T* b, uint32_t number);
    };
    
    #include "Model.h"
    template <class T>
    void Model::build(T* b, uint32_t number)
    {
        //implementation
    }
    
    void TemporaryFunction()
    {
        Model m;
        m.build<B1>(new B1(),1);
        m.build<B2>(new B2(), 1);
        m.build<B3>(new B3(), 1);
    }