The strange behaviour when using c++ specialization template - c++

I am newbie in programming with c++ template. I have 3 code files
main.cpp
#include "template_test.h"
#include <iostream>
using namespace std;
int main()
{
mytest<int> mt;
mt.method(1);
system("pause");
return 0;
}
template_test.h
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
template_test.cpp
#include "template_test.h"
//empty
The code takes effective in VS2013. However when I change my code to 2 sitiuations, there are both something wrong with my code.
1.The first is with the linker error code.
main.cpp
#include "template_test.h"
#include <iostream>
using namespace std;
int main()
{
mytest<int> mt;
mt.method(1);
system("pause");
return 0;
}
template_test.h
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input);
};
template<class T>
void mytest<T>::method(T input)
{
cout << " " << endl;
}//explicit specialization here
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
template_test.cpp
#include "template_test.h"
//empty
2.The second output nothing instead of the correct answer 'ok'.
main.cpp
#include "template_test.h"
#include <iostream>
using namespace std;
int main()
{
mytest<int> mt;
mt.method(1);
system("pause");
return 0;
}
template_test.h
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template_test.cpp
#include "template_test.h"
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}//move from .h to .cpp file here
The strange behaviour of c++ template makes me confused. So, what's the problem?

The first problem is caused by the fact that your explicit specialization
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
is defined in the header file and outside the class definition and without the keyword inline.
An explicit specialization causes an actual function (rather than a mere template) to be defined. That definition will occur in every translation unit, so if you compile template_test.cpp and main.cpp separately, the definition of the function will be included in both object files, causing a multiple-definition error at linking time (because it's a violation of the ODR, the one-definition-rule).
You best avoid this either by including the function definition inside the class template definition (by specializing the entire class template for int), or using the keyword inline:
template<>
inline void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
The second problem is caused by the fact that a template specialization must always be declared before it is used:
(14.7.3/6) If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined. [...]
Since your main.cpp includes the header file, but not the .cpp file, the declaration of the template specialization is not known when it is used in main.cpp. You solve this best by including the specialization in the header file, either inside the class template definition (by specializing the entire class template for int), or using the keyword inline outside the class template definition.

You second question first. Remember a rule when using template. Do not separate the template implementation to a cpp file. Make them all in one .h file.
You first code compiles fine in my VC2012, I am not sure what's wrong with VC2013.

Related

Why my inline functions have linking error?

I am learning C++ and currently testing inline functions. If I run my code now I will have linking error, but if I change
inline void Test::print40()
to
void Test::print40()
everything would be fine. Could you explain to me why I have an error and how to use inline function in this case.
// main.cpp file
#include "Test.h"
using namespace std;
int main()
{
Test obj1;
obj1.print40();
}
// Test.cpp file
#include <iostream>
#include "Test.h"
inline void Test::print40()
{
std::cout << "40";
}
// Test.h file
#pragma once
class Test
{
public:
void print40();
};
Inline function definition shall be in each compilation unit where it is ODR used.
On the other hand in your project the compilation unit main does not know that the function is an inline function. So it can not find its definition.
Move this definition from Test.cpp
#pragma once
class Test
{
public:
void print40();
};
inline void Test::print40()
{
std::cout << "40";
}
to the header Test.h.
The module Test.cpp is redundant.
As the function is very simple and short then it could be defined in the class definition as for example
class Test
{
public:
void print40()
{
std::cout << "40";
}
};
In this case it will be an inline function by default.

MSVC compilation failure on explicit variadic template function instantiation

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.

Method Calling from header files

I have a programming assignment where I'm supposed to write up the code for inserting and removing linked lists. However I haven't used C++ in a while and am struggling remember certain things.
Right now, I am simply trying to put a prototype method in a header file, define it in my cpp file, and then call it in my main method. this is what I have.
LinkedList.h
#include <iostream>
using namespace std;
class LinkedList {
public:
void testPrint();
};
LinkedList.cpp
#include "LinkedList.h"
int main() {
LinkedList::testPrint();
}
void LinkedList::testPrint() {
cout << "Test" << endl;
}
I am getting the following errors
a nonstatic member reference must be relative to a specific object
'LinkedList::testPrint': non-standard syntax; use & to create a pointer to member
LinkedList::testPrint() is a member function.
It is not declared static, so that means it must be called on a particular object, defined as LinkedList linked_list, for example. Then use linked_list.testPrint().
Option 1 - static member function declaration
#include <iostream>
using namespace std;
class LinkedList {
public:
static void testPrint();
};
int main() {
LinkedList::testPrint();
}
void LinkedList::testPrint() {
cout << "Test" << endl;
}
Option 2 - Instantiated object with call to member function
#include <iostream>
using namespace std;
class LinkedList {
public:
void testPrint();
};
int main() {
LinkedList linked_list;
linked_list.testPrint();
}
void LinkedList::testPrint() {
cout << "Test" << endl;
}

Incomplete declaration of a partially specialized template

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).

undefined reference to `std::ostream& SpyOutput::operator<< <double>(double const&)'

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