编写C++。只有头文件的库? < >我编译C++静态库,因为所有的类都是模板化的,类定义和实现都在头文件中。因此,(在VisualStudio2005下)似乎需要创建一个包含所有其他头文件的.cpp文件,以便将其正确编译到库中

编写C++。只有头文件的库? < >我编译C++静态库,因为所有的类都是模板化的,类定义和实现都在头文件中。因此,(在VisualStudio2005下)似乎需要创建一个包含所有其他头文件的.cpp文件,以便将其正确编译到库中,c++,code-organization,C++,Code Organization,这是为什么?即使创建.cpp文件,也不会收到任何内容。您需要实例化模板,以便将它们放入库中 看看这里 关于如何用具体类型实例化模板。编译器不编译头文件,因为头文件要包含在源文件中。在进行任何编译之前,预处理器从任何包含的头文件中获取所有代码,并将这些代码放在包含它们的源文件中,即包含它们的位置。如果编译器也应该编译headerfile,那么您可能会在许多事情上有多个定义 例如,这是预处理器看到的: [foo.h] void foo(); [mysource.cpp] void foo();

这是为什么?

即使创建.cpp文件,也不会收到任何内容。您需要实例化模板,以便将它们放入库中

看看这里
关于如何用具体类型实例化模板。

编译器不编译头文件,因为头文件要包含在源文件中。在进行任何编译之前,预处理器从任何包含的头文件中获取所有代码,并将这些代码放在包含它们的源文件中,即包含它们的位置。如果编译器也应该编译headerfile,那么您可能会在许多事情上有多个定义

例如,这是预处理器看到的:

[foo.h]
void foo();
[mysource.cpp]
void foo();

int main()
{
   foo();
}
--

这就是编译器看到的:

[foo.h]
void foo();
[mysource.cpp]
void foo();

int main()
{
   foo();
}

想想标准模板库。当您在另一个项目中使用模板类时,它们将被编译。

其他人所说的关于未编译到库中的模板的话是正确的。但是,编译器仍然很难让它们看到(由包含在.CPP文件中的它们),这样,它们至少会被检查为语法。C++中的

< P>,模板只是实际类的元定义。编译模板类时,编译器实际上会为传入的特定类型的数据动态生成实际类的代码(模板只是要复制的“模式”)

e、 g.如果您有以下代码


struct MyTemplate
{
private:
    float MyValue;

public:
    float Get() { return MyValue; }
    void Set(float value) { MyValue = value; }
};

void main()
{
    MyTemplate v1;
    MyTemplate v2;
    v1.Set(5.0f);
    v2.Set(2);
    v2.Get();
}
编译器实际看到的是


struct CompilerGeneratedNameFor_MyTemplate_float
{
private:
    float MyValue;

public:
    float Get() { return MyValue; }
    void Set(float value) { MyValue = value; }
};

struct CompilerGeneratedNameFor_MyTemplate_int
{
private:
    int MyValue;

public:
    int Get() { return MyValue; }
    void Set(int value) { MyValue = value; }
};

void main()
{
    CompilerGeneratedNameFor_MyTemplate_float v1;
    CompilerGeneratedNameFor_MyTemplate_int v2;
    v1.Set(5.0f);
    v2.Set(2);
    v2.Get();
}
正如您可能看到的,编译器实际上不知道要生成什么代码,直到您实际声明了模板的实例。这意味着模板无法编译到库中,因为它不知道模板最终将是什么。好消息是,如果只分发包含模板定义的头文件,实际上不需要编译或包含任何库


另外,作为旁注,“#include”预编译器命令实际上只是告诉预编译器将“#include”替换为该文件中的所有内容。

您试图创建一些不必要的内容。大多数C库(和所有C++库)都被分配为两部分:

  • 接口(
    foo.h
  • 实现(
    foo.lib
对于C++模板代码,所有库必须由最终用户编译,因为模板是这样工作的。没有理由提供预编译库。在这种情况下,您可以将您的库分发想象为:

  • 接口(
    foo.h
  • 实现(
    foo inl.h

正如Niel在上面所说的,只为您自己的测试目的而实现是很有用的,并且可能值得将这些实现与库本身一起分发。所以你应该有一套单独的单元测试来测试你的代码;但是这些测试不应该是库本身的一部分。

您不需要生成.lib。如果您所有的类都是模板,请查看boost或stlport,因为它们没有发布的.lib[1]

模板在使用时进行编译


[1] 严格来说,他们为更高级的功能(如正则表达式、iostream等)分发库,但辅助库由其他模板使用,模板本身不是以库的形式分发的。

如果所有代码都在.h文件中,则不需要编译静态库来使用代码


所有代码在编译时都可供库使用,因此在链接时不需要任何代码。

如果库都是在头文件中实现的,则不需要构建任何二进制文件来使用它。也就是说。我通常在头文件库的初始开发阶段创建一个.cpp文件。为什么?编译器在实际使用模板之前不会尝试编译甚至解析模板。有一个.cpp文件和一些用于实例化模板的伪代码可以帮助我在开发过程中更早地发现语法错误。所以我可以添加一些模板代码,点击编译,修复语法错误,添加更多代码,编译…等等。如果你每次都在添加数百行代码后试图找出一些愚蠢的语法错误,你就会明白我的意思了。一旦我的库准备好进行单元测试,我将删除.cpp文件并依靠单元测试来驱动我的开发

另外,如果只使用VC++编译代码,那么需要注意的一点是,VC++在实际使用之前不会尝试编译所有模板成员函数。例如:

template <typename T>
class MyTemplate
{
public:
    MyTemplate() {} // default constructor

    MyTemplate(int) { 
        1 = 2
        // other syntax error code here
    }
};

void f() { MyTemplate<int> myt(); } // compile fine in VC
void g() { MyTemplate<int> myt(1); } // syntax error 
模板
类MyTemplate
{
公众:
MyTemplate(){}//默认构造函数
MyTemplate(int){
1 = 2
//这里有其他语法错误代码
}
};
void f(){MyTemplate myt();}//在VC中编译良好
void g(){MyTemplate myt(1);}//语法错误

使用VC++2003可以很好地编译f(),而g++将捕获语法错误。我认为VC8和VC9也有同样的问题。

编写一组单元测试比强制创建一个不需要存在的静态库要好。毕竟,如果模板代码没有被调用,许多编译器将错过模板代码的基本错误。