******* EDIT *******
One reader suggested that my question was a duplicate of the question found here. The leading response to this question gives two solutions:
- 1) #include the implementation file at the end of the header (which is what I did in my solution) or
- 2) explicitly instantiate all of the template instances I'll need at the end of the implementation file
Since I had already attempted this solution, this is not a duplicate question.
The problem, as addressed by Ben Voigt below (thank you), has to do with Visual Studio. Changing the "Item Type" from "C/C++ compiler" to "C/C++ header" for the MyClass.cpp file resolved the issue.
**** END EDIT ****
I'm a beginner to c++ and I'm running into an issue trying to compile the following program in Visual Studio 2015. The program compiled fine using the clang compiler on my Mac. The program also compiled fine using cl.exe from the Developer Command Prompt for VS2015. I guess this means something is configured wrong in my Visual Studio project, but I haven't found a solution.
Here's the code:
/** @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();
}
When I combine these files in one directory and run the command:
cl test.cpp
from the Developer Command Prompt for VS2015, it correctly compiles. I get a test.exe executable file which returns:
test.exe
Hello! My item is: foo
Hello! My item is: 7
So far, so good.
The problem begins when I try to complete this project inside of Visual Studio 2015. I started an "Empty Project" for Visual c++ and added these exact same files. However, when I build the project I get the error messages:
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
The error message leads me to believe that I have a circular dependency. The culprit appears to be the #include "MyClass.cpp"
in the MyClass.h file, but this is necessary for the template to compile. Without this inclusion, the compiler cannot see the instantiation of the template and does not know the actual data type corresponding to the generic type ItemType
(or so my textbook says).
In an effort to satisfy the Visual Studio build process, I removed the #include "MyClass.cpp
from the MyClass.h file, but then I get THESE errors:
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
There were six such errors (only three are shown), all being unresolved external symbols.
At this point I don't know what else to try. If I include the implementation file in the header, the compiler yells at me for having circular dependencies, and if I DON'T include the implementation file in the header, I have unresolved external symbols.
Any help on this problem would be much appreciated :)