c ++编译问题 - 使用cl.exe编译好但不能从Visual Studio 2015编译

时间:2017-01-05 22:34:31

标签: c++ visual-studio-2015

*******编辑*******

一位读者建议我的问题与找到的问题here重复。对这个问题的主要回答提供了两个解决方案:

  • 1)#include标题末尾的实现文件(这是我在解决方案中所做的)或
  • 2)显式实例化我在实现文件末尾需要的所有模板实例

由于我已尝试过此解决方案,因此这不是一个重复的问题。

问题,正如下面的Ben Voigt所解决的(谢谢),与Visual Studio有关。更改"项目类型"来自" C / C ++编译器"到" C / C ++标题"因为MyClass.cpp文件解决了这个问题。

****结束编辑****

我是c ++的初学者,我遇到了尝试在Visual Studio 2015中编译以下程序的问题。使用我的Mac上的clang编译器编译好的程序。该程序还使用VS2015的Developer Command Prompt中的cl.exe进行了编译。我想这意味着在我的Visual Studio项目中配置错误,但我还没有找到解决方案。

以下是代码:

/** @file MyInterface.h */

#ifndef MY_INTERFACE_
#define MY_INTERFACE_

template<class ItemType>
class MyInterface
{
public:
    virtual void sayHello() const = 0;
};

#endif
/** @file MyClass.h */

#ifndef MY_CLASS_
#define MY_CLASS_

#include "MyInterface.h"

template<class ItemType>
class MyClass : public MyInterface<ItemType>
{
private:
    ItemType myItem;

public:
    MyClass();
    void setItem(const ItemType& newItem);
    void sayHello() const;
};

#include "MyClass.cpp"
#endif
/** Implementation file for MyClass.
    @file MyClass.cpp */

#include "MyClass.h"
#include <iostream>

template<class ItemType>
MyClass<ItemType>::MyClass()
{
}

template<class ItemType>
void MyClass<ItemType>::setItem(const ItemType& newItem)
{
    myItem = newItem;
}

template<class ItemType>
void MyClass<ItemType>::sayHello() const
{
    std::cout << "Hello! My Item is: " << myItem << std::endl;
}
/** @file test.cpp */

#include "MyClass.h"
#include <string>

int main()
{
    MyClass<std::string> classOne;
    classOne.setItem("foo");
    classOne.sayHello();

    MyClass<int> classTwo;
    classTwo.setItem(7);
    classTwo.sayHello();
}

当我将这些文件合并到一个目录中并运行命令时:

cl test.cpp

来自VS2015的开发人员命令提示符,它正确编译。我得到一个test.exe可执行文件,它返回:

test.exe
Hello! My item is: foo
Hello! My item is: 7

到目前为止,非常好。

当我尝试在Visual Studio 2015中完成此项目时,问题就开始了。我开始了一个#34;空项目&#34;对于Visual c + +并添加了这些完全相同的文件。但是,当我构建项目时,我收到错误消息:

Error   C2995   'MyClass<ItemType>::MyClass(void)': function template has already been defined
Error   C2995   'void MyClass<ItemType>::setItem(const ItemType &)': function template has already been defined
Error   C2995   'void MyClass<ItemType>::sayHello(void) const': function template has already been defined

错误消息让我相信我有循环依赖。罪魁祸首似乎是MyClass.h文件中的#include "MyClass.cpp",但这对于模板编译是必要的。如果没有这种包含,编译器就无法看到模板的实例化,也不知道与泛型类型ItemType对应的实际数据类型(或者我的教科书说的那样)。

为了满足Visual Studio构建过程,我从MyClass.h文件中删除了#include "MyClass.cpp,但后来我收到了这些错误:

Error   LNK2019 unresolved external symbol "public: __thiscall MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)" (??0?$MyClass@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAE@XZ) referenced in function _main
Error   LNK2019 unresolved external symbol "public: __thiscall MyClass<int>::MyClass<int>(void)" (??0?$MyClass@H@@QAE@XZ) referenced in function _main
Error   LNK2019 unresolved external symbol "public: void __thiscall MyClass<int>::setItem(int const &)" (?setItem@?$MyClass@H@@QAEXABH@Z) referenced in function _main

有六个这样的错误(只显示了三个),都是未解析的外部符号。

此时我不知道还有什么可以尝试。如果我将实现文件包含在头文件中,编译器会因为存在循环依赖关系而对我大吼大叫,如果我不在头文件中包含实现文件,那么我有未解析的外部符号。

非常感谢有关此问题的任何帮助:)

1 个答案:

答案 0 :(得分:2)

因为你#include MyClass.cpp,它本身不是一个编译单元,它是一个头文件。确保Visual Studio被告知不要单独构建它,默认情况下它假定.h文件是标题,.cpp是每个单独编译的单元。

访问项目属性并将“项目类型”从“C / C ++编译器”更改为“C / C ++标题”。

enter image description here

这有效地将构建命令更改为工作版本

cl test.cpp

来自通过添加所有文件生成的默认(有效)命令

cl test.cpp MyClass.cpp

如果您在命令行输入错误,则会导致完全相同的错误。

还有其他方法可以完成从构建命令中删除它,例如在解决方案资源管理器的右键菜单中找到的“从项目中排除文件”,但这使得编辑/导航不太方便。将其正确标记为头文件将为您提供调试期间Intellisense自动完成,Goto定义和源视图的最佳体验。