How to use templates while separating header and implementation files? - c++

I'm trying to implement a Template while separating the Header and Implementation file.
I'm getting this error when building the project:
error C2955: 'Series': use of class template requires template
argument list
Header.h
#ifndef SERIES_H
#define SERIES
template <class T>
class Series {
private:
T var;
public:
Series(T v);
};
#endif
Implementation.cpp
#include <iostream>
#include "Header.h"
template <class T>
Series::Series(T v) {
var = v;
std::cout << var;
}
Main.cpp
#include <iostream>
#include "Header.h"
int main() {
Series<int> w(10);
}
The project builds successfully when everything is in one file
What do I need to do to make this work?

Related

dllexport class template instances (specializations), reducing compilation time for header-only template libraries

Is it possible to export some of the class template instances, while leaving to a library's user the ability of generating other specializations of a given class template (when compiling the executable).
Given I have a public header
// public.h
#pragma once
#ifndef DLL_BUILD
#define API __declspec(dllimport)
#else
#define API __declspec(dllexport)
#endif // !DLL_BUILD
#include <type_traits>
// dummy to generate .lib
struct API dummy
{
void be_dummy();
};
template <class T>
struct Foo
{
static T Sum(T a, T b)
{
static_assert(std::is_fundamental_v<T>);
return a + b;
}
};
With this way of declaring class template Foo every instantiation will happen inside the user's executable.
However, if I define Foo as dllexport/dllimport using API macro, every specialization of Foo which has not been explicitly instantiated inside the dll, will fail to link.
// impl.cpp - dll
#include "public.h"
void dummy::be_dummy()
{
volatile int a = 0;
return;
}
template API struct Foo<int>;
///////////////////////////////////////////
// main.cpp - executable
#include "public.h"
#include <iostream>
int main()
{
dummy().be_dummy();
// std::cout << Foo<double>().Sum(4.12, 3.18) << std::endl; // Unresolved external symbol
std::cout << Foo<int>().Sum(60, 9) << std::endl; // executed within the dll
return 0;
}
So, is it possible to force the compiler to link against an existing class template instance when one has been exported, and to generate another that has not.
UPDATE
I found a solution, see my answer below.
I leave the old update just in case anybody will find such usage of SFINAE helpful.
UPDATE OLD
I found one cumbersome solution involving SFINAE, but it results in defining a class template twice, therefore is very error prone. I don't know if it can be wrapped up with macro in a manner that will make it possible to write it only once.
// public.h
#pragma once
#ifndef DLL_BUILD
#define API __declspec(dllimport)
#else
#define API __declspec(dllexport)
#endif // !DLL_BUILD
#include <type_traits>
namespace templ_export
{
template <class T>
struct is_exported : std::false_type {};
// this can be placed to a separated header (i.e. Exported.hpp)
template <> struct is_exported<int> : std::true_type {};
template <class T>
struct API FooExported
{
static T Sum(T a, T b)
{
//static_assert(std::is_fundamental_v<T>);
return a + b;
}
};
template <class T>
struct FooNotExported
{
static T Sum(T a, T b)
{
//static_assert(std::is_fundamental_v<T>);
return a + b;
}
};
template <class T, bool = templ_export::is_exported<T>()>
struct GetFooExported
{
using type = FooNotExported<T>;
};
template <class T>
struct GetFooExported<T, true>
{
using type = FooExported<T>;
};
}
template <class T>
using Foo = typename templ_export::GetFooExported<T>::type;
/////////////////////////////////
// impl.cpp
#include "public.h"
void dummy::be_dummy()
{
volatile int a = 0;
return;
}
template struct API templ_export::FooExported<int>;
Here is a simple way of exporting class template instances.
On Dll creation compiler must think, that Foo is defined as dllexport. But while creating an Executable and linking to that Dll, Foo class template must not have any declspec attributes applied to it. Though we need to declare particular class template instances as dllimport.
// public.h
#pragma once
#ifndef DLL_BUILD
#define API __declspec(dllimport)
#else
#define API __declspec(dllexport)
#endif // !DLL_BUILD
// define T_API emplty for library users, hence they will see just 'struct Foo'
#ifndef T_API
#define T_API
#endif
#include <type_traits>
template <class T>
struct T_API Foo
{
static T Sum(T a, T b)
{
//static_assert(std::is_fundamental_v<T>);
return a + b;
}
};
// impl.cpp
// Compile with DLL_BUILD defined
// define T_API for library build
#define T_API __declspec(dllexport)
#include "public.h"
void dummy::be_dummy()
{
volatile int a = 0;
return;
}
// instantiating class template
template struct T_API Foo<int>;
For executable:
// Exported.h
// this header needs to be shipped alongside with public.h and included after
#pragma once
// declare template instance as imported
template struct __declspec(dllimport) Foo<int>;
// main.cpp
// Executable linked to library
#include "public.h"
#include "Exported.h"
int main()
{
dummy().be_dummy();
// Sum is called from Executable
std::cout << Foo<double>().Sum(4.12, 3.18) << std::endl;
// Sum is called from Dll
std::cout << Foo<int>().Sum(60, 9) << std::endl;
return 0;
}
I consider this approach to be useful for header-only template libraries. Like precompiled headers, dll with class template instances will reduce compilation time.

C++ template: <class> does not name a type

Newbie to C++ so please forgive me. I'm trying to write a simple template class to implement the Stack data structure functionality. I've read through this question to understand how template declaration and implementation works: Why can templates only be implemented in the header file?. But I would like to use the solution where class declaration and implementation are separate (not defined inline in .h).
MyStack.h:
#include "StackNode.h"
#include "MyStack.tpp"
template <typename T>
class MyStack
{
private:
StackNode<T> *top;
public:
MyStack();
virtual ~MyStack();
};
MyStack.tpp:
#include "MyStack.h"
template <typename T>
MyStack<T>::MyStack()
: top(nullptr)
{
}
template <typename T>
MyStack<T>::~MyStack()
{
}
main.cpp:
#include "MyStack.h"
int main() {
MyStack<int> myStack;
return 0;
}
However compiling the above gives this error:
../src/MyStack.tpp:11:1: error: 'MyStack' does not name a type
../src/MyStack.tpp:18:1: error: 'MyStack' does not name a type
I know I'm missing something, but don't understand what. Thanks!
The problem is that you are including the .tpp file, which contains the class method definitions, before the class has actually been declared yet. You need to move that #include statement below the class declaration instead.
Also, the .tpp file should not be #include'ing the .h file that originally #include'd it. In fact, that won't work correctly since your .h file is missing header guards to prevent multiple inclusions within the same translation unit (ie, main.cpp in this case). So, you would end up with MyStack.h which includes MyStack.tpp which includes MyStack.h again, which causes an error when it tries to re-declare things that are already declared. Always declare a header guard in your .h files.
Try this instead:
MyStack.h:
#ifndef MyStack_H
#define MyStack_H
#include "StackNode.h"
template <typename T>
class MyStack
{
private:
StackNode<T> *top;
public:
MyStack();
virtual ~MyStack();
};
#include "MyStack.tpp"
#endif
MyStack.tpp:
template <typename T>
MyStack<T>::MyStack()
: top(nullptr)
{
}
template <typename T>
MyStack<T>::~MyStack()
{
}

How to properly use Templates?

I am trying to create a vector class that looks something like this:
template <typename T>
class Vector
{
.
.
.
};
#include "vector.cpp"
However, when I start writing my functions in "vector.cpp", CLion complains that I have duplicate functions. How do I work around this? I believe in NetBeans, I can add vector.h & vector.cpp to a folder called "Important Files" which would fix the problem. I am not sure what the equivalent in CLion is.
General Design of a template
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
// Needed includes if any
// Prototypes or Class Declarations if any
template<class T> // or template<typename T>
class Example {
private:
T item_;
public:
explicit Example( T item );
~Example();
T getItem() const;
};
#include "Example.inl"
#endif // EXAMPLE_H
Example.inl
// Class Constructors & Member Function implementations
template<class T>
Example<T>::Example( T item ) : item_(item) {
}
template<class T>
Example<T>::~Example() {
}
template<class T>
T Example<T>::getItem() const {
return item_;
}
Example.cpp
#include "Example.h"
// Only need to have the include here unless if
// the class is non template or stand alone functions
// are non-template type. Then they would go here.

Problems with file inclusion for variadic class

I have a variadic template class and I'm trying to include my namespace which is in another file so that I can use a few functions from it in the class.
However, the file including the namespace also includes a using statement related to the class as I need the variadic class for a few functions in that namespace as well.
I have many errors trying to do this and was wondering if there is a way to achieve my goal...
Here is what I mean:
#include "VariadicClass.hpp"
#include <stdint.h>
using VariadicClass3 = VariadicClass<3, int>
namespace mynamespace {
int function1(VariadicClass3 param){return 1;}
int function2(){return 0;}
}
////////////////////////////////////////////
#include "MyNamespace.hpp"
#include <stdint.h>
template<std::size_t T_size, typename T>
class VariadicClass3 {
public:
//...
void function1(){
auto some_var = mynamespace::function2();
}
};
You have couple of typos in your posted code. Ignoring that for the time being, you can use forward declaration as shown below to remove the cyclic dependency:
MyNamespace.hpp:
#pragma once
#include <cstdint>
// Forward declare the class.
template<std::size_t T_size, typename T> class VariadicClass;
using VariadicClass3 = VariadicClass<3, int>;
namespace mynamespace {
// Use the class only in reference in declaration.
// If the implementation of the function needs to
// access to members of VariadicClass3, it needs to be
// in a .cpp file where VariadicClass.hpp can be #include'd.
int function1(VariadicClass3 const& param){return 0;}
int function2(){return 1;}
}
VariadicClass.hpp:
#pragma once
#include "MyNamespace.hpp"
template<std::size_t T_size, typename T>
class VariadicClass {
public:
//...
void function1(){
auto some_var = mynamespace::function2();
}
};

c++ templated friend class

I'm trying to write an implementation of a 2-3-4 tree in c++. I'm it's been a while since I've used templates, and I'm getting some errors. Here's my extremely basic code framework:
node.h:
#ifndef TTFNODE_H
#define TTFNODE_H
template <class T>
class TreeNode
{
private:
TreeNode();
TreeNode(T item);
T data[3];
TreeNode<T>* child[4];
friend class TwoThreeFourTree<T>;
int nodeType;
};
#endif
node.cpp:
#include "node.h"
using namespace std;
template <class T>
//default constructor
TreeNode<T>::TreeNode(){
}
template <class T>
//paramerter receving constructor
TreeNode<T>::TreeNode(T item){
data[0] = item;
nodeType = 2;
}
TwoThreeFourTree.h
#include "node.h"
#ifndef TWO_H
#define TWO_H
enum result {same, leaf,lchild,lmchild,rmchild, rchild};
template <class T> class TwoThreeFourTree
{
public:
TwoThreeFourTree();
private:
TreeNode<T> * root;
};
#endif
TwoThreeFourTree.cpp:
#include "TwoThreeFourTree.h"
#include <iostream>
#include <string>
using namespace std;
template <class T>
TwoThreeFourTree<T>::TwoThreeFourTree(){
root = NULL;
}
And main.cpp:
#include "TwoThreeFourTree.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
int main(){
ifstream inFile;
string filename = "numbers.txt";
inFile.open (filename.c_str());
int curInt = 0;
TwoThreeFourTree <TreeNode> Tree;
while(!inFile.eof()){
inFile >> curInt;
cout << curInt << " " << endl;
}
inFile.close();
}
And when I try to compile from the command line with:
g++ main.cpp node.cpp TwoThreeFourTree.cpp
I get the following errors:
In file included from TwoThreeFourTree.h:1,
from main.cpp:1:
node.h:12: error: ‘TwoThreeFourTree’ is not a template
main.cpp: In function ‘int main()’:
main.cpp:13: error: type/value mismatch at argument 1 in template parameter list for ‘template<class T> class TwoThreeFourTree’
main.cpp:13: error: expected a type, got ‘TreeNode’
main.cpp:13: error: invalid type in declaration before ‘;’ token
In file included from node.cpp:1:
node.h:12: error: ‘TwoThreeFourTree’ is not a template
In file included from TwoThreeFourTree.h:1,
from TwoThreeFourTree.cpp:1:
node.h:12: error: ‘TwoThreeFourTree’ is not a template
My main question is why it's saying "error: ‘TwoThreeFourTree’ is not a template". Does anyone have any ideas? Thanks for all advice/help in advance...
Dan
The solution that has been accepted has the slight problem of opening your class to any instantiation of the TwoThreeFourTree template, not only those that share the same instantiation type.
If you only want to open the class to instantiations of the same type you can use the following syntax:
template <typename T> class TwoThreeFourTree; // forward declare the other template
template <typename T>
class TreeNode {
friend class TwoThreeFourTree<T>;
// ...
};
template <typename T>
class TwoThreeFourTree {
// ...
};
You just need to declare it as a template when you use the friend keyword. You're using incorrect syntax for a friend declaration in your code. What you want to write is:
template <class U> friend class TwoThreeFourTree;