Is there any way to make constructor understand parameter type automatically? - c++

I have a Feature class which has a public vehicle_type in it and I have 3 candidates for vehicle_type variable which are; Car,Truck and Motor classes. When I call constructor for Feature class, well I want my program to get which vehicle type was called with constructor automatically. I actually tried to use Templates for the problem but it didn't work. So, can someone tell me how to achieve this with or without using Templates.
This is my Feature.h file:
#ifndef FEATURE_H
#define FEATURE_H
#include <string>
#include "../includes/Car.h"
#include "../includes/Truck.h"
#include "../includes/Motor.h"
template <typename T>
class Feature{
public:
Feature();
Feature(int w, std::string b, std::string clr, double p, T v_t);
T vehicle_type;
int wheels;
std::string brand;
std::string color;
double price;
};
#endif
This is my Feature.cpp file:
# include "../includes/Feature.h"
template <typename T>
Feature::Feature(int w, std::string br, std::string clr, double p, T v_t){wheels = w; brand=br; color = clr; price=p; vehicle_type = v_t; }
Feature::Feature(){}
and lastly, this below is the error occurs when I hover my mouse on Feature constructor in the Feature.cpp file.
name followed by '::' must be a class or namespace name
Feel free to ask for more information. Thanks.

It looks like you just need to supply the template declaration and the fix the syntax:
template <typename T>
Feature<T>::Feature(int w, std::string br, std::string clr, double p, T v_t);
template<class T>
Feature<T>::Feature();

Related

Understanding how imports are working in C++

I'm trying to understand how including works in C++. I have two questions about it. The first one is on how properly import the .h file. For example I created the following HashNode.h file:
namespace HashNode{
template<class Data>
class HashNode{
private:
Data data;
HashNode *next;
public:
explicit HashNode(const Data &data);
Data getKey();
~Node();
};
}
So in the HashNode.cpp file, it should like:
#include "HashNode.h"
using namespace HashNode;
template <class Data> // ~~~ HERE 1 ~~~
HashNode::HashNode(const Data &data) {//todo};
template <class Data> // ~~~ HERE 2 ~~~
Data* HashNode::getKey() {
//todo
}
HashNode::~Node() {
//todo
}
This way it works but do I have to include template <class Data> beside each function which uses Data? Why it does not recognize Data without including template <class Data>?
Also I have created the Hash.h file which should use the HashNode.h file:
#include "HashNode.h"
using namespace HashNode;
namespace Hash {
template <class Data>
class Hash {
typedef enum {
GOOD = 0,
BAD = -1,
BAD_ALLOC = -2
} Status;
private:
HashNode **hash;
int capacity;
int size;
public:
explicit Hash(int size);
Status insertData(const Data &data);
~Hash();
};
}
But I get the the following error: Can't resolve type 'HashNode'. Why it can't see the import?
In the Hash.cpp file I get Unused import statement for #include "HashNode.h". Why is that?
Also, what if I want to include private functions - should them be in the .h file or in the .cpp file?
The member functions of a template class are themselves also templates. Because of this, they need to be defined with any required template parameters and template type definitions.
About your second question, it has to do with namespaces. As I see it, having namespace and class under the same naming might cause you ambiguity. Although, everything seems to be fine on the structural side of the code. Try using #pragma once or some kind of guards to prevent this kind of issues.

C++ template not recognizing data types

I have the following simplified code where the compiler is not recognizing the data types and I am not sure why. In the code, I want to be able to pass a map, where the keywords can either be a std::string, a char, or an int. I also want the user to be able to choose whether the associated value is a float or double. In addition, based on the type of the associated value I want the return to either be std::vector<float> or std::vector<double>. Due to the variability in data types, I choose to code this problem as a template.
// main.cpp
#include "test.hpp"
#include <iostream>
#include <math.h>
#include <map>
#include <tuple>
double func6(std::map<char, double> arr);
int main(int argc, const char * argv[]) {
std::map<char, double> inputs;
inputs['x'] = 2.0;
inputs['y'] = 5.438;
std::tuple<std::vector<double>, std::vector<double>> answer;
ODESolver q;
answer = q.ode_solver(inputs, func6);
// - The line below this was tried and it did not work
// any better than the line of code above this.
// answer = q.ode_solver<char, double>(inputs, func6);
return 0;
}
double func6(std::map<char, double> arr)
{
return arr['y'] * log(arr['y']) / arr['x'];
}
The .hpp file has the following information.
#ifndef test_hpp
#define test_hpp
#include <stdio.h>
#include <tuple>
#include <vector>
#include <map>
#include <functional>
class ODESolver
{
public:
template<class char_type, class real_type>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const std::function<real_type(std::map<char_type, real_type>)>& func)
{
// - This function does not work with the function call
// as written
// - The code in this function is irrelevant, it was just
// created to have returnable information of the correct
// type to test the function call
std::vector<real_type> one = {0.0, 1.0};
std::vector<real_type> two = {0.0, 1.0};
std::tuple<std::vector<real_type>, std::vector<real_type>> three(one, two);
return three;
}
};
#endif /* test_hpp */
The compiler does not allow the template shown above, because it does not recognize a matching function call for answer= q.ode_solver(inputs, func6) in the main program. However, if I replace the std::function statement with the following code it works fine.
template<class char_type, class real_type>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const std::function<double(std::map<char, double>)>& func)
All I am doing is replacing the templated parameters with the parameters I want to use in this exact situation, but that defeats the reason for using a template. I have also tried calling the function with answer = q.ode_solver<char, double>(inputs, func6); and it still does not recognize the function. What am I missing?
Implicit conversions (from the function pointer to std::function in this case) won't be considered in template argument deduction.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
You can add an explicit conversion, e.g.
answer = q.ode_solver(inputs, static_cast<std::function<double(std::map<char, double>)>>(func6));
or specify the template arguments explicitly (I'm not sure why you said it didn't work, see the live demo linked below)
answer = q.ode_solver<char, double>(inputs, func6);
LIVE
Or just add another template parameter instead of using std::function.
template<class char_type, class real_type, class F>
static inline std::tuple<std::vector<real_type>, std::vector<real_type>>
ode_solver(std::map<char_type, real_type> &inputs,
const F& func)

Why am I getting "no matching function for call to '…'" with template function?

With the below code:
materia.h:
#ifndef MATERIA_H
#define MATERIA_H
class material
{
public:
template <class type>
static material* MakeMaterial(typename type::configtype, long);
template <class type>
void CreateNaturalForm(typename type::configtype, long);
…
};
template <class type>
material* material::MakeMaterial(typename type::configtype Config, long Volume)
{
return type::Spawn(Config, Volume);
}
#endif
materias.h:
#ifndef MATERIAS_H
#define MATERIAS_H
#include "materia.h"
#include "confdef.h"
class solid : public material {
public:
typedef solidmaterial configtype;
…
};
template material* material::MakeMaterial<solid>(solidmaterial, long);
template <class type>
void material::CreateNaturalForm(typename type::configtype Config, long Volume)
{
…
MakeMaterial(Config, Volume); // Error here
…
}
template void material::CreateNaturalForm<solid>(solidmaterial, long);
#endif
confdef.h:
#ifndef CONFDEF_H
#define CONFDEF_H
enum solidmaterial {
WOOD,
…
};
#endif
main.cpp
#include "materia.h"
#include "materias.h"
#include "confdef.h"
int main()
{
material::MakeMaterial(WOOD, 500); // Same error here
}
(Here's an online version of the above code that reproduces the error.)
I get the following compilation error message on the commented line:
No matching function for call to 'MakeMaterial'
What am I doing wrong? Shouldn't the explicit instantiation allow the compiler to see the correct function?
The code compiles if I write MakeMaterial<solid> explicitly, but the whole point here is to deduce type from the Config argument. How can I achieve this?
In the call
MakeMaterial(Config, Volume); // Error here
the compiler is asked to find a match where type::configtype in the function template, is the type of Config.
But nothing tells the compiler what to match type to: this is not an explicit instantiation.
In general there could be hundreds of types that type could be matched to, where type::configtype would be the type of Config. C++ does not support the special case where there is only one such possible type.
How to fix that depends on what you meant to accomplish.

C++ access to members of an inherited class, where the inherited class is a template parameter

I am working with the libMesh FEM library and am trying to develop a class (EqCore) that inherits from libMesh. This class will provide some additional features that are inherited again by a class that I want to actually use (MainEq).
The two functions, set_constant and get_constant, are causing the error below. These worked as shown with a different inheritance scheme (see Inheritance of template class with a template member function in C++). The difference with this problem is that now the template parameter (Type) is actually a class that gets inherited. Is this a dangerous practice?
I would appreciate any help getting this code working or finding an alternate method.
ERROR MESSAGES:
In member function ‘void EqCore::set_constant(std::string, ParamType)’:
test_libmesh.cpp:26:57: error: expected primary-expression before ‘>’ token
In member function ‘ParamType EqCore::get_constant(std::string)’:
/home/slaughter/Documents/programs/source/test_libmesh.cpp:31:76: error: expected primary-expression before ‘>’ token
PROGRAM:
//! \example test_libmesh.cpp
#include <string>
using std::string;
// libMesh includes
#include <libmesh.h>
#include <libmesh_common.h>
#include <equation_systems.h>
#include <transient_system.h>
#include <explicit_system.h>
#include <parameters.h>
#include <mesh.h>
using namespace libMesh;
// Fundamental behavior that will be used among many classes
template <typename Type> class EqCore : Type{
public:
// Class constructor
EqCore(EquationSystems& sys, string name) : Type(sys, name, 1){}
// A function for storing a constant value (causes error)
template<typename ParamType> void set_constant(std::string name, ParamType var){
Type::get_equation_systems().parameters.set<ParamType>(name) = var;
}
// A function for retrieving a constant value (causes error)
template<typename ParamType> ParamType get_constant(std::string name){
ParamType output = Type::get_equation_systems().parameters.get<ParamType>(name);
return output;
}
};
// A test class derived
class MainEq : public EqCore<ExplicitSystem>{
public:
// Constructor
MainEq(EquationSystems& sys) : EqCore(sys, "main"){ }
};
// Begin main function
int main (int argc, char** argv){
// Initialize libMesh and create an empty mesh
LibMeshInit init (argc, argv);
Mesh mesh;
// Test w/o any of the above classes
EquationSystems eq_sys(mesh);
eq_sys.parameters.set<double>("test1") = 1;
printf("Test 1: %f\n", eq_sys.parameters.get<double>("test1"));
// Test my class set/get functions
MainEq eq(eq_sys);
eq.set_constant<double>("test2", 2);
printf("Test 2: %f\n", eq.get_constant<double>("test2"));
}
Because you are inside a template, the compiler cannot determine that set is a template automatically during parse time, and it's assuming that set is a non-template, and hence the parse fails.
The solution is to explicitly inform the compiler that set is a member template, as such.
Type::get_equation_systems().parameters.template set<ParamType>(name) = var
In C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond, by David Abrahams, Aleksey Gurtovoy (Amazon) it is explained as follows:
double const pi = 3.14159265359;
template <class T>
int f(T& x)
{
return x.convert<3>(pi);
}
T::convert might be a member function template, in which case the
highlighted code passes pi to a specialization of convert<3>. It
could also turn out to be a data member, in which case f returns
(x.convert < 3 ) > pi. That isn't a very useful calculation, but the
compiler doesn't know it.
The template keyword tells the compiler that a dependent name is a
member template:
template <class T>
int f(T& x)
{
return x.template convert<3>(pi);
}
If we omit template, the compiler assumes that x.convert does not
name a template, and the < that follows it is parsed as the less-than
operator.

"class template has already been declared as a non-class template"

Hey i'm getting this odd error when I leave the namespace sf{ declaration in the later code:
1>c:\libraries and headers\sfml\sfml-1.6-sdk-windows-vc2008\sfml-1.6\include\sfml\graphics\body.h(70): error C2989: 'sf::Body' : class template has already been declared as a non-class template
1>c:\libraries and headers\sfml\sfml-1.6-sdk-windows-vc2008\sfml-1.6\include\sfml\graphics\body.h(11): error C3856: 'sf': class is not a class template
The code worked fine when it wasn't a template class for the past 3 weeks, With the same sf::Body class name; i just recently changed it to make it more flexible. Can i not declare a template class inside a namespace or what?
Here's the code:
#include <SFML/Graphics.hpp>
#include <vector>
#include <math.h>
#include <cmath>
namespace sf{ //when i take this out and the closing bracket the code runs fine
template<typename drawable>
class Body : public sf::Drawable{
private:
sf::Vector2f MoveVal;
std::vector<drawable> Drawables;
public:
Body(const Vector2f& Position = Vector2f(0, 0), const Vector2f& Scale = Vector2f(1, 1), float Rotation = 0.f, const Color& Col = Color(255, 255, 255, 255)){
SetPosition(Position);
SetScale(Scale);
SetRotation(Rotation);
SetColor(Col);};
// Overide Drawable Functions To Detect any Movement
void SetX(float X){
MoveVal.x += X - GetPosition().x;
Drawable::SetX(X);};
void SetY(float Y){
MoveVal.y += Y - GetPosition().y;
Drawable::SetY(Y);};
// Regular Functions
void AddObject(drawable& Object){
Object.Move(GetX(),GetY());
Drawables.push_back(Object);};
void DestroyObject(unsigned short Index){
Drawables.erase(Drawables.begin()+Index);};
void Clear(){
Drawables.clear();};
drawable& GetObject(unsigned short index)
{return Drawables[index];};
unsigned int GetNumbObjects()
{return Drawables.size();};
void Draw(sf::RenderTarget& target){
for(unsigned short I=0; I<Drawables.size(); I++){
//Body offset
Drawables[I].SetPosition(
Drawables[I].GetPosition().x + MoveVal.x,
Drawables[I].GetPosition().y + MoveVal.y);
} // TODO: add tint based on overall Body Color
target.Draw(*this);
//Reset all the Change Values
MoveVal.x=0;
MoveVal.y=0;
};
void Render(sf::RenderTarget& target) const{
for(int I=0; I< Drawables.size(); I++)
Drawables[I].Draw(target);
};
};// Body Class
} //namespace sf
Ok found the problem:
In a previously included header file: Shape.hpp I declare Body as a friend with the following syntax:
friend class Body;
Which apparently makes the compiler assume Body is not a template (no template indication is made)
The correct syntax was:
template <typename drawable>
friend class Body;
Because now the compiler understands Body as a template class
The two most likely candidates based on your information are that Graphics.hpp has mismatched { } or that you had a forward declaration of class Body without marking it a template.
sf::Body is a name that seems to be already taken (for a class whereas you're declaring a template). Are you sure you want to put your code in the sf namespace? It's more customary to use one's own namespaces rather than those of the libraries they use.