STD error: wrong number of template arguments (1, should be 3) - c++

I have three class. One is abstract, second is based on the abstract one and its storing pointers in std::vector to instances of another.
I want to create std::shared_ptr of ClientRepository to pass it to the Manager class instance in the future.
There is a template class called "Repository". I want to use it to create a few types of Repositories, for example: CarsRepository, ItemsRepository, etc.
Unfortunately I am getting an error while compiling:
main.cpp:84:139: error: template argument 1 is invalid
std::shared_ptr, std::vector> > p = std::make_shared;
^
Repository.hpp
#ifndef REPOSITORY_HPP
#define REPOSITORY_HPP
#include <string>
template<typename typeBOOL, typename typeShared_ptr, typename VectorOfSmarPtrs > class Repository
{
protected:
VectorOfSmarPtrs nameOfVector;
public:
virtual typeBOOL create(const typeShared_ptr&) = 0;
};
#endif
ClientRepository.hpp
#ifndef CLIENTREPOSITORY_HPP
#define CLIENTREPOSITORY_HPP
#include <memory>
#include <string>
#include "Client.hpp"
#include "Repository.hpp"
class ClientRepository : public Repository<bool, std::shared_ptr<Client>, std::vector<std::shared_ptr<Client> > >{
public:
bool create(const std::shared_ptr<Client> & newClient) override;
};
#endif
ClientRepository.cpp
include "ClientRepository.hpp"
bool ClientRepository::create(const std::shared_ptr<Client> & newClient) {
if(newClient != NULL){
for(int i = 0; i < this->nameOfVector.size(); i++) {
if(this->nameOfVector.at(i)->GetPersonalID() == newClient->GetPersonalID()) {
return 0;
}
}
this->nameOfVector.push_back(newClient);
return 1;
}
else return 0;
}
main.cpp
#include <iostream>
#include <memory>
#include "Client.hpp"
#include "ClientRepository.hpp"
#include "Repository.hpp"
int main(){
ClientRepository x;
std::shared_ptr<Repository< bool, std::shared_ptr<Client>, std::vector<std::shared_ptr<Client>> > p = std::make_shared<ClientRepository>;
}
What is wrong with this code? What should I change?

You miss parenthesis:
std::shared_ptr<Repository<bool,
std::shared_ptr<Client>,
std::vector<std::shared_ptr<Client>>>> p
// ^
= std::make_shared<ClientRepository>();
// ^^

Related

Undefined reference when compiling when using header and cpp file with templates in one of them

I've been trying to compile my project and I've encountered some problems when trying so. The error in particular that appears is:
[build] /usr/bin/ld: CMakeFiles/robot_control.dir/main.cpp.o:(.data.rel.ro._ZTVN4comm15cameraInterfaceE[_ZTVN4comm15cameraInterfaceE]+0x10): undefined reference to `comm::Interface<cv::Mat>::callbackMsg()'
My project is organized right now as it follows:
-${HOME_WORKSPACE}
|-main.cpp
|-src
|-communication.cpp
|-communication.hpp
The header file (communication.hpp) is:
#include <opencv2/opencv.hpp>
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <algorithm>
#ifndef COMM_GUARD
#define COMM_GUARD
namespace comm
{
struct lidarMsg
{
float angle_min, angle_increment, range_min, range_max;
int nranges, nintensities;
std::vector<int> ranges;
};
template <typename T>
class Interface
{
public:
Interface() : received{false} {};
virtual void callbackMsg();
bool receptionAccomplished()
{
return this -> received;
}
T checkReceived()
{
return this -> elementReceived;
}
protected:
bool received;
T elementReceived;
};
class cameraInterface : public Interface<cv::Mat>
{
public:
void callbackMsg(ConstImageStampedPtr &msg);
};
class lidarInterface : public Interface<lidarMsg>
{
public:
void callbackMsg(ConstLaserScanStampedPtr &msg);
};
}
#endif
The source file (communication.cpp) is:
#include <opencv2/opencv.hpp>
#include <algorithm>
#include <iostream>
#include "communication.hpp"
#ifndef COMM_CPP_GUARD
#define COMM_CPP_GUARD
namespace comm
{
void cameraInterface::callbackMsg(ConstImageStampedPtr &msg)
{
std::size_t width = msg->image().width();
std::size_t height = msg->image().height();
const char *data = msg->image().data().c_str();
cv::Mat im(int(height), int(width), CV_8UC3, const_cast<char *>(data));
im = im.clone();
cv::cvtColor(im, im, cv::COLOR_RGB2BGR);
this->elementReceived = im;
received = true;
}
void lidarInterface::callbackMsg(ConstLaserScanStampedPtr &msg) {
this->elementReceived.angle_min = float(msg->scan().angle_min());
this->elementReceived.angle_increment = float(msg->scan().angle_step());
this->elementReceived.range_min = float(msg->scan().range_min());
this->elementReceived.range_max = float(msg->scan().range_max());
this->elementReceived.nranges = msg->scan().ranges_size();
this->elementReceived.nintensities = msg->scan().intensities_size();
for (int i = 0; i < this->elementReceived.nranges; i++)
{
if (this->elementReceived.ranges.size() <= i)
{
this->elementReceived.ranges.push_back(std::min(float(msg->scan().ranges(i)), this->elementReceived.range_max));
}
else
{
this->elementReceived.ranges[i] = std::min(float(msg->scan().ranges(i)), this->elementReceived.range_max);
}
}
}
}
#endif
The main file(main.cpp) includes the following header:
#include <gazebo/gazebo_client.hh>
#include <gazebo/msgs/msgs.hh>
#include <gazebo/transport/transport.hh>
#include <opencv2/opencv.hpp>
#include <opencv2/calib3d.hpp>
#include <iostream>
#include <stdlib.h>
#include "src/communication.hpp"
I included the part of the #ifndef /#define /#endif since it is a solution that I found to this kind of problem in other problem. I've been toggling the CMakeLists.txt file but still no solution that could solve this error.
You can't do this:
virtual void callbackMsg();
You have to actually provide the implementation for all template methods within the .h file.

Object slicing in Inventory system

I'm working on an inventory system for a game and I'm hitting a brick wall with object slicing; I'm losing variables on a reference to a derived class.
Below is an excerpt in which a T-shirt is created in the main game file, and then passed to a players inventory for storage. However only the variables present in the base class Item are preserved.
game.cpp
#include "Item.h"
#include "Clothes.h"
#include "Shirts.h"
shirt_item white_shirt = shirt_item(materialDescriptor::cotton, colourDescriptor::white);
player.getComponent<InventoryComponent>().storeItem(&whiteShirt);
InventoryComponent.cpp
bool InventoryComponent::storeItem(Item *inItem)
{
if (freeInvSpace() > 0)
{
items.push_back(inItem);
return true;
}
else if (freeInvSpace() < 0)
{
std::cout << "ERROR! Inventory over filled somehow" << std::endl;
}
return false;
}
InventoryComponent.h
#pragma once
#include "Components.h"
#include "Item.h"
#include "Clothes.h"
#include "Shirts.h"
class InventoryComponent : public Component // Entity component system
{
public:
std::vector<Item*> items;
InventoryComponent(int inSize)
{
size = inSize;
}
bool storeItem(Item *inItem);
...
}
Item.h
#pragma once
#include <string>
class Item
{
public:
std::string name,
description;
bool pronoun;
};
Clothes.h
#pragma once
#include <vector>
#include <string>
#include "Item.h"
#include "materialDescriptor.h"
#include "colourDescriptor.h"
class Clothes : public Item
{
public:
materialDescriptor material;
std::vector<bodyParts> coverage;
colourDescriptor colour;
Clothes(std::string inName, std::string inDescription, materialDescriptor inMaterial, colourDescriptor colour, bool inPronoun = false)
{
name = inName;
description = inDescription;
material = inMaterial;
pronoun = inPronoun;
}
Clothes() {}
};
Shirts.h
#pragma once
#include "Clothes.h"
#include "materialDescriptor.h"
#include "colourDescriptor.h"
class shirt_item : public Clothes
{
public:
shirt_item(materialDescriptor inMaterial, colourDescriptor inColour)
{
material = inMaterial;
colour = inColour;
description = "A basic shirt that covers the wearer from the elements";
name = "T-Shirt"
}
}
ECS.h
#pragma once
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <bitset>
#include <array>
#include "Components.h"
class Component
{
public:
Entity* entity;
virtual void init() {}
virtual void update() {}
virtual void draw() {}
virtual ~Component() {}
private:
};
class Entity
{
private:
bool active = true;
std::vector<std::unique_ptr<Component>> components;
ComponentArray componentArray;
ComponentBitSet componentBitSet;
public:
template <typename T> T& getComponent() const
{
auto ptr(componentArray[getComponentTypeID<T>()]);
return *static_cast<T*>(ptr);
}
}
Using Vs2019 break points, the constructor for the T-shirt works but as soon as I attempt to use the object it is boiled down to it's base class: Item > Clothes > Shirts
If you pass and store inherited objects through pointers you eventually have to store them on the heap. Instead you are creating them on the stack. Just do
auto white_shirt = std::make_unique<shirt_item>(materialDescriptor::cotton, colourDescriptor::white);

How to solve "Does not name a type" error

I am getting the following error:
'class name' does not name a type for all of my classes.
I suspect it may be a circular dependency but I have no clue how to solve it as each class requires access to a function from the next. Below are my classes:
Container.h:
#ifndef CONTAINER_H
#define CONTAINER_H
#include "Factory.h"
class Container
{
public:
Container()
{
array = new int[10];
for (int i = 0; i < 10; ++i) {
array[i] = i;
}
}
Iterator* createIterator()
{
Factory fac;
return fac.factoryMethod();
}
friend class Iterator;
private:
int* array;
};
#endif //CONTAINER_H
Factory.h:
#ifndef FACTORY_H
#define FACTORY_H
#include "Iterator.h";
class Factory
{
Iterator* factoryMethod(Container* con)
{
return new Iterator(con);
}
};
#endif //FACTORY_H
Iterator.h:
#ifndef ITERATOR_H
#define ITERATOR_H
#include "Container.h"
class Iterator
{
public:
Iterator(Container* con)
{
this->con =con;
}
int getFromIndex(int i)
{
return con->array[i];
}
private:
Container* con;
};
#endif //ITERATOR_H
main.cpp:
#include <iostream>
using namespace std;
#include "Container.h"
#include "Iterator.h"
int main() {
Container con;
Iterator* it = con.createIterator();
cout<<it->getFromIndex(2)<<endl;
return 0;
}
Thank you in advance for any help.
It is indeed a circular dependency between your headers. Container.h includes Factory.h, which includes Iterator.h, which includes Container.h.
The solution is to move the implementations of member functions from header files into source files. That way, header files will only need declarations, not definitions, of the classes, which you can easily put directly in the "consuming" header files:
class Iterator;
class Container
{
public:
Container();
Iterator* createIterator();
friend class Iterator;
private:
int* array;
};
Then, in an appropriate source file (such as Container.cpp), implement the member functions and include any headers you need:
Container.cpp
#include "Container.h"
#include "Factory.h"
Container::Container() : array(new int[10])
{
for (int i = 0; i < 10; ++i) {
array[i] = i;
}
}
Iterator* Container::createIterator()
{
Factory fac;
return fac.factoryMethod();
}
(Dtto for Factory and Iterator, of course).
Don't forget to link all the source files together when building your final binary.

Using CRTP as an alternative to abstract static methods in C++11

I'm trying to implement a generic resource manager which would ensure that every resource gets only loaded once with C++11.
My first attempt:
resourcemanager.h
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#include <map>
#include <memory>
template<typename T>
class ResourceManager {
public:
static std::shared_ptr<T> load(std::string filePath);
private:
static map<std::string, std::weak_ptr<T>> resources;
virtual static std::shared_ptr<T> loadResource(std::string filePath) = 0;
};
#endif // RESOURCEMANAGER_H
#include "resourcemanager.h"
resourcemanager.cpp
using namespace std;
template<typename T>
map<string, weak_ptr<T>> ResourceManager<T>::resources;
template<typename T>
shared_ptr<T> ResourceManager<T>::load(std::string filePath) {
auto search = resources.find(filePath);
if (search != resources.end()) {
auto ptr = search->second.lock();
if (ptr) {
return ptr;
}
}
auto ptr = loadResource(filePath);
resources[filePath] = ptr;
return ptr;
}
However since abstract static methods are apparently forbidden black magic I tried to use CRTP:
resourcemanager.h
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#include <map>
#include <memory>
template<typename T, class Derived>
class ResourceManager {
public:
static std::shared_ptr<T> load(std::string filePath);
private:
static std::map<std::string, std::weak_ptr<T>> resources;
static std::shared_ptr<T> loadResource(std::string filePath);
};
#endif // RESOURCEMANAGER_H
resourcemanager.cpp
#include "resourcemanager.h"
using namespace std;
template<typename T, class Derived>
map<string, weak_ptr<T>> ResourceManager<T, Derived>::resources;
template<typename T, class Derived>
shared_ptr<T> ResourceManager<T, Derived>::load(string filePath) {
auto search = resources.find(filePath);
if (search != resources.end()) {
auto ptr = search->second.lock();
if (ptr) {
return ptr;
}
}
auto ptr = ResourceManager::loadResource(filePath);
resources[filePath] = ptr;
return ptr;
}
template<typename T, class Derived>
shared_ptr<T> ResourceManager<T, Derived>::loadResource(string filePath) {
return Derived::loadResource(filePath);
}
This looks like it should do what I want. However when I try to use it, it fails at the linking stage:
managedstring.h
#ifndef MANAGEDSTRING_H
#define MANAGEDSTRING_H
#include "resourcemanager.h"
class ManagedString {
public:
ManagedString(std::string filePath);
std::string get();
private:
std::shared_ptr<std::string> ptr;
class StringManager : public ResourceManager<std::string, StringManager> {
private:
static std::shared_ptr<std::string> loadResource(std::string filePath);
};
};
#endif // MANAGEDSTRING_H
managedstring.cpp
#include "managedstring.h"
using namespace std;
ManagedString::ManagedString(string filePath) {
ptr = StringManager::load(filePath);
}
string ManagedString::get() {
return *ptr;
}
shared_ptr<string> ManagedString::StringManager::loadResource(string filePath) {
// dummy implementation
return make_shared<string>("foo");
}
main.cpp
#include <iostream>
#include "managedstring.h"
using namespace std;
int main() {
ManagedString string1 = ManagedString("bar");
ManagedString string2 = ManagedString("foobar");
cout << string1.get() << endl;
cout << string2.get() << endl;
}
When I try to compile this with g++ -std=c++11 -o bin -Wall main.cpp managedstring.cpp resourcemanager.cpp (using gcc version 5.3.0) I get this error message:
/tmp/ccgqljOQ.o: In function `ManagedString::ManagedString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
managedstring.cpp:(.text+0xdd): undefined reference to `ResourceManager<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >,
ManagedString::StringManager>::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
Should this work? Is this a compiler shortcoming? Or am I trying to do something I shouldn't do.
I also thought about altering my design, however I think it's not that bad. Feel free to disagree with me on this.
In resourcemanager.h, this line:
#include "resourcemanager.h"
Should be:
#include "resourcemanager.cpp"
This seems valid only for your first example, but the same applies to all the others too.
Otherwise, as an alternative, put both declarations and definitions of template classes in the same file.

Undefined reference when using template [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have a templated class named DataHandler
#ifndef DATAHANDLER_H
#define DATAHANDLER_H
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <set>
#include "constants.h"
template <typename T>
using Car = std::pair< T, T>;
template <typename T>
using SparseMatrix = std::vector< Car<T> >;
template <class T>
class DataHandler
{
public:
// initializes a new DataHandler only if none has been created,
// otherwise return the living instance
static DataHandler<T>* getInstance()
{
if(!dataHandler)
dataHandler = new DataHandler();
return dataHandler;
}
void readFile();
SparseMatrix<T>* getSparseBlue(){ return &sparseBlue; }
SparseMatrix<T>* getSparseRed(){ return &sparseRed; }
virtual ~DataHandler();
private:
// static DataHandler to ensure only one instance can be created
static DataHandler<T> *dataHandler;
// private constructor to use DataHandler as a Singleton
DataHandler();
int numElem = 0;
int m_rows, m_cols = -1;
#endif // DATAHANDLER_H
The source file is:
#include "data_handler.h"
#include <fstream>
#include <algorithm>
#include <omp.h>
#include <chrono>
using namespace std;
using namespace constants;
// Global static pointer used to ensure a single instance of the class.
template<typename T>
DataHandler<T>* DataHandler<T>::dataHandler = NULL;
template<typename T>
DataHandler<T>::DataHandler()
{
//ctor
}
template<typename T>
DataHandler<T>::~DataHandler()
{
//dtor
}
template<typename T>
void DataHandler<T>::readFile()
{
// do some stuff
}
// Instantiation of relevant templates
template class DataHandler<unsigned char>;
template class DataHandler<unsigned short int>;
In the last two lines I instantiate the templates which I define in main.cpp:
#include <iostream>
#include <chrono>
#include <fstream>
#include <algorithm>
#include "data_handler.h"
#include "dense_traffic_handler.h"
#include "sparse_traffic_handler.h"
#include "constants.h"
using namespace std;
// Check the number of rows/cols to choose between char or short int for the sparse case
bool matrixIsSmall()
{
return true;
}
void integerCase()
{
typedef unsigned char T;
DataHandler<T> *dh = DataHandler<T>::getInstance();
dh->readFile();
DenseTrafficHandler dth(dh); // ****** ERROR HERE *****
}
void charCase()
{
typedef unsigned char T;
DataHandler<T> *dh = DataHandler<T>::getInstance();
dh->readFile();
DenseTrafficHandler dth(dh); // ****** ERROR HERE *****
SparseTrafficHandler<T> sth;
set<unsigned short int> step = dh->getstep();
int currentStep = 0;
set<unsigned short int>::const_iterator stepToSave = step.begin();
}
int main(int argc, char *argv[])
{
if(matrixIsSmall())
charCase();
else
integerCase();
return 0;
}
Compiler gives me an error: undefined reference to DenseTrafficHandler::DenseTrafficHandler<unsigned short>(DataHandler<unsigned short>*)
DenseTrafficHandler header is like that:
#ifndef TRAFFICHANDLER_H
#define TRAFFICHANDLER_H
#include "constants.h"
#include "data_handler.h"
class DenseTrafficHandler
{
public:
template<typename T>
DenseTrafficHandler(DataHandler<T> *dh);
virtual ~DenseTrafficHandler();
private:
int m_cols, m_rows;
char* data;
char ** dense = NULL;
};
#endif // TRAFFICHANDLER_H
DenseTrafficHandler source is:
#include "dense_traffic_handler.h"
using namespace std;
using namespace constants;
template <typename T>
DenseTrafficHandler::DenseTrafficHandler(DataHandler<T> *datah)
{
DataHandler<T> *dh = datah;
dense = dh->getDense();
m_rows = dh->getm_rows();
m_cols = dh->getm_cols();
}
DenseTrafficHandler::~DenseTrafficHandler()
{
//dtor
}
So I have two questions:
Why do I receive this error and how can I manage it?
Is there a way in DataHandler source to not specify
template <typename T>
DataHandler<T>::functionName() for every function? (I mean something like using namespace Datahandler<T>)
You receive this error because compiler did not generate the code for this template type. One of solutions is to tell the compiler to do this explicitly by template instantiation:
add to your DenseTrafficHandler.cpp:
template class DenseTrafficHandler<unsigned short>;
Yes, just implement it in the header file. Reading more about it here.