/* MyClass.h */
class MyClass
{
public:
template <typename T>
void Foo(const T &val);
};
/* MyClass.cpp */
#include <string>
#include <iostream>
#define EXPLICIT_INSTANTIATION_FOO(MyType) \
template void MyClass::Foo(const MyType &val)
EXPLICIT_INSTANTIATION_FOO(int);
EXPLICIT_INSTANTIATION_FOO(float);
EXPLICIT_INSTANTIATION_FOO(std::string);
template <typename T>
void MyClass::Foo(const T &val)
{
std::cout << "My Value: " << val << std::endl;
}
For some other reason, I couldn't define the Foo in the header file, then I try to explicitly instantiate all the types I need in the source file. And it works pretty well on g++-4.8.
Then once it I submit the codes, I find the building failed on Windows 10, x86_64, cl19. It was an unresolved symbol error there and was look like my instantiations weren't be exposed from the object.
But interestingly, when I try to reproduce this error on my own Windows by making that simple snippet above. I found it works well on my vs2017 with cl19...
There would be thousands of configuration differs between the company and the personal machine, but I just don't have any idea that what would be the reason why the instantiations don't work there... Any ideas appreciated! :)
SUPPLEMENTS:
FYI, the complete codes are here:
/* MyClass.h */
#pragma once
class MyClass
{
public:
MyClass();
~MyClass();
template <typename T>
void Foo(const T &val);
};
/* MyClass.cpp */
#include "MyClass.h"
#include <iostream>
#include <string>
#define EXPLICIT_INSTANTIATION_FOO(MyType) \
template void MyClass::Foo(const MyType &val)
EXPLICIT_INSTANTIATION_FOO(int);
EXPLICIT_INSTANTIATION_FOO(float);
EXPLICIT_INSTANTIATION_FOO(std::string);
MyClass::MyClass() {}
MyClass::~MyClass() {}
template <typename T>
void MyClass::Foo(const T &val)
{
std::cout << "My Value: " << val << std::endl;
}
/* main.cpp */
#include "MyClass.h"
#include <iostream>
#include <string>
int main()
{
std::string v = "hello";
MyClass cls;
cls.Foo(v);
std::cin.get();
return 0;
}
Which passed the compilation on msvc.
Move the function definition to before the EXPLICIT_INSTANTIATION_FOO invocations. This is something that never should have worked but compilersllowed, they are slowly coming around on it. If you want to make msvc reject it use the /permissive- flag.
Thanks, everybody, this silly question is solved.
The reason is the template instantiations will not inherit the dllexport attribute from the template definition on Windows. And obviously, it works on my silly test codes because it wasn't compiled as the DLL :)
Related
I've distilled my problem to a small example, pardon the macros. It seems a similar problem from this post is no longer an issue in VS and compiles fine. I believe I have a more specialized version of this problem that hasn't been fixed but want to make sure I'm not missing something. The following code compiles in GCC and runs expectedly, but gives error C2893 (Failed to specialize function template) in VS:
Macros.h:
#define If(x) \
template<class T,class...Args, typename std::enable_if<std::is_same<T, x>::value>::type* = nullptr>
#define Do void Func(Args... args)
Definition.cpp:
#include <string>
#include <iostream>
#include "Macros.h"
using namespace std;
int answer = 42;
double pie = 3.14;
string s = "Hello World";
// Function Definitions
If(int) Do { cout << answer << endl; }
If(double) Do { cout << pie << endl; }
If(string) Do { cout << s << endl; }
// Explicit Instantiations
template void Func<int>(int, double, string);
template void Func<double>();
template void Func<string>();
Usage.cpp:
#include <string>
#include <type_traits>
#include "Macros.h"
// Template Function Declaration
If(T) Do;
int main() {
using namespace std;
Func<int>(5, 2.0, string("hello"));
Func<double>();
Func<string>();
}
As with the example in the other post it works correctly if the instantiations come from actual use in a function. Doing so is simple with this example but not so simple with my code.
So I declared a template class called my_class and I use this class in another file, "main.cpp".
I included "my_class.h" in my main.cpp and I'm getting unknown type name error, anyone know what's going on?
Here is some code:
// "my_class.h"
#ifndef TYPE_H_DEFINE
#define TYPE_H_DEFINE
#include <vector>
#include <algorithm>
namespace wtvr {
template<class T>
class my_class {
public:
void add(const T&);
const T& get();
private:
std::vector<T> my_class_vec;
};
template<class T>
void my_class<T>::add(const T& obj) {
my_class_vec.push_back(obj);
}
template<class T>
const T& my_class<T>::get() {
std::random_shuffle(my_class_vec.begin(), my_class_vec.end());
return my_class_vec[0];
}
}
#endif
It was a tricky one!
Turns out that my include guard names
#ifndef TYPE_H_DEFINE
#define TYPE_H_DEFINE
was already used by the standard c++ library so I changed it to a different name, no wonder why Bjarne Stroustrup hates macros!! Thank you everybody!
Here is the code for the question:
PlainInterface.h
/** PlainInterface.h */
#ifndef _PLAIN_INTERFACE
#define _PLAIN_INTERFACE
#include <vector>
template <class ItemType>
class PlainInterface{
public:
virtual int getSize () const = 0;
};
#endif
Plain.h
/** Plain.h */
#ifndef _PLAIN
#define _PLAIN
#include "PlainInterface.h";
template <class ItemType>
class Plain: public PlainInterface < ItemType > {
private:
std::vector<ItemType> a;
public:
Plain();
~Plain();
int getSize() const;
};
#include "Plain.cpp"
#endif
Plain.cpp
/* Plain.cpp */
#include <iostream>
#include "Plain.h"
//Constructors
template <class ItemType>
Plain<ItemType>::Plain() {
std::cout << "Created\n";
}
template <class ItemType>
Plain<ItemType>::~Plain() {
std::cout << "Destroyed\n";
}
template <class ItemType>
int Plain<ItemType>::getSize() const { return 0; }
So according to this question it said that you can either have all of the implementation in the header file, or put #include "Plain.cpp" at the end of the "Plain.h" file, or put the explicit instantiations at the end of the "Plain.cpp" file. I would like to keep the files seperate and not limit what is allowed into the templates. I tried the second option and it didn't work.
The errors that I am getting are that the constructor/deconstructor/getSize definitions in Plain.cpp are already defined. What am I doing wrong here?
You should remove #include "Plain.h" in your .cpp file, as you are creating a circular include otherwise.
Example:
//a.h
...
#include "b.cpp"
//b.cpp
#include "a.h"
a will include b, b will include a, and so on. This is probably why the second option you mentioned didn't work.
Here another answer that applies to your problem (I think): https://stackoverflow.com/a/3127374/2065501
I am trying to partially specialize the std::hash struct for my own class TestHandle, and this class has its implementation split up using the opaque pointer idiom. So I am trying to provide the impl class with its own std::hash specialization. But I am running into templating problems.
Could someone help me understand why this is happening? I have attached all the necessary code below.
TestHandle.h
#pragma once
#include <memory>
class TestHandle {
public:
TestHandle();
void print();
class Impl;
std::unique_ptr<Impl> implementation;
};
TestHandle.cpp
#include "TestHandle.h"
#include "Impl.h"
#include <iostream>
using std::cout;
using std::endl;
TestHandle::TestHandle() : implementation{new TestHandle::Impl} { }
void TestHandle::print() {
this->implementation->print();
cout << "Hash of this->implementation is "
<< std::hash<TestHandle::Impl>()(*this->implementation) << endl;
}
Impl.h
#pragma once
#include "TestHandle.h"
#include <functional>
class TestHandle::Impl {
public:
void print();
int inner_integer;
};
namespace std {
template <> struct std::hash<TestHandle::Impl>;
}
Impl.cpp
#include "TestHandle.h"
#include "Impl.h"
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
namespace std {
template <> struct hash <TestHandle::Impl> {
size_t operator() (const TestHandle::Impl& implementation) {
return std::hash<int>()(implementation.inner_integer);
}
};
}
void TestHandle::Impl::print() {
cout << "Printing from impl" << endl;
}
I am compiling with the following command
g++ -std=c++14 -c Impl.cpp TestHandle.cpp
and am getting the following error
TestHandle.cpp:11:12: error: invalid use of incomplete type 'std::hash<TestHandle::Impl>'
<< std::hash<TestHandle::Impl>()(*this->implementation) << endl;
template <> struct std::hash<TestHandle::Impl>;
Just forward declares the specialisation. It doesn't have to implement all the method (or any) of the original template. The compiler has no idea about the operator().
You will need to define the struct (in place of just the declaration);
template <> struct hash <TestHandle::Impl> {
size_t operator() (const TestHandle::Impl& implementation) const noexcept;
};
Side note: you will also need to provide the primary template (via inclusion) of <functional> (missing in the original listed code).
I'm trying to intercept "the data" from standard output (for this question I'm working with cout). Also for this question I'm working with double, but the program should be able to handle any primitive data type. When I try to compile my code I get this error:
undefined reference to `std::ostream& SpyOutput::operator<<
(double const&)' collect2: error: ld returned 1 exit status
this is my main:
#include "SpyOutput.h"
#define endl '\n'
int main ( int argc, char *argv[], char *env[] ) {
double d1 = 12.3;
SpyOutput spy(&cout);
spy << d1;
return 0;
}
this is my header file:
#include <iostream>
using namespace std;
class SpyOutput {
private:
ostream* output;
public:
SpyOutput(ostream* os);
template <class T>
ostream &operator<<(const T &x);
};
this is my implementation file:
#include "SpyOutput.h"
SpyOutput::SpyOutput(ostream* os){
output = os;
}
template <class T>
ostream& SpyOutput::operator<<(const T &x){
// SOME CODE GO HERE
return *output;
}
I have googled this error (and similar) without finding a working solution, thanks in advance for any help or hint that you can provide to me! :-)
What's the problem?
For an explanation why it doesn't compile, see "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?"
As an example, consider the header file foo.h which contains the following template function declaration:
// File "foo.h"
template<typename T>
void foo();
Now suppose file foo.cpp actually defines that template function:
// File "foo.cpp"
#include <iostream>
#include "foo.h"
template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}
Suppose file main.cpp uses this template function by calling foo():
// File "main.cpp"
#include "foo.h"
int main() { foo<int>(); ... }
If you compile and link these two .cpp files, most compilers will generate linker errors. Because in order for the compiler to generate the code, it must see both the template definition (not just declaration) and the specific types/whatever used to "fill in" the template. If the template body is defined in the .cpp the compiler won't see it and hence won't generate any code for it.
How to fix it?
There is more than one possible solution around this issue. I suggest moving the definition of the template function into the .h file.
// File "foo.h"
template<typename T>
void foo()
{
std::cout << "Here I am!\n";
}
In your source you can call it as usual:
// File "main.cpp"
#include "foo.h"
int main() { foo<int>(); ... }
You need to place your template implementation of SpyOutput::operator<< into the header file