I’m trying to call a function template defined inside a class from within another class, but I’m stuck.
I get error:
1>class1.obj : error LNK2019: riferimento al simbolo esterno "public: void __thiscall class2::output<double,long>(double,long,float)" (??$output#NJ#class2##QAEXNJM#Z) non risolto nella funzione "public: void __thiscall class1::x(class class2 &)" (?x#class1##QAEXAAVclass2###Z)
1>class1.obj : error LNK2019: riferimento al simbolo esterno "public: void __thiscall class2::output<float,int>(float,int,float)" (??$output#MH#class2##QAEXMHM#Z) non risolto nella funzione "public: void __thiscall class1::y(class class2 &)" (?y#class1##QAEXAAVclass2###Z)
1>C:\xxx.exe : fatal error LNK1120: 2 esterni non risolti
If I uncomment lines with duplicate functions (the ones without templates) it is ok.
Can you help fix it?
File: “class1.h”
#ifndef CLASS1
#define CLASS1
#include "class2.h"
class class1{
public:
void x(class2& c );
void y(class2& c );
};
#endif
File: “class1.cpp”
#include "class1.h"
void class1::x( class2& c )
{
double img;
long integ;
float y;
c.output(img, integ, y);
}
void class1::y(class2& c )
{
float img;
int integ;
float y;
c.output(img, integ, y);
}
File: “class2.h”
#ifndef CLASS2
#define CLASS2
class class2{
void output2(double img, long integ, float y);
void output2(float img, int integ, float y);
public:
template <typename T1, typename T2>
void output(T1 img, T2 integ, float y);
//void output(double img, long integ, float y);
//void output(float img, int integ, float y);
};
#endif
File: “class2.cpp”
#include "class2.h"
template <typename T1, typename T2>
void class2::output(T1 img, T2 integ, float y)
{output2(img, integ, y);}
//void class2::output(double img, long integ, float y)
//{output2(img, integ, y);}
//void class2::output(float img, int integ, float y)
//{ output2(img, integ, y);}
void class2::output2(double img, long integ, float y){/*...*/}
void class2::output2(float img, int integ, float y){/*...*/}
EDIT
I’m talking about function templates and not class templates. I’ve seen the question I would be duplicating before, but it is not what I’m looking for.
I have two functions inside a class that are identical except for their parameters type.
I only wanted a simple trick to avoid writing and maintaining identical code for two functions inside the same class.
Anyway I’ve found a solution, adding these two lines at the bottom of class2.cpp:
template void class2::output<double, long>(double img, long integ, float y);
template void class2::output<float, int>(float img, int integ, float y);
If you want a specialization you need to implement the "default" template function in the .h file and define which specializations you are implementing. In the .cpp file you simply implement the specializations.
File: "class2.h"
#ifndef CLASS2
#define CLASS2
class class2{
public:
template <typename T1, typename T2>
void class2::output(T1 img, T2 integ, float y)
{ /* .. do stuff.. */}
};
template <>
void class2::output(double img, long integ, float y);
#endif
File: “class2.cpp”
#include "class2.h"
template <>
void class2::output(double img, long integ, float y)
{ /* .. do specialized stuff.. */}
Related
I wanted to move some code that I wrote, on my laptop, to my other PC. I didn't use Github or any other type of source control, I just simply copied the c++ files on to a USB drive and put them on my other PC.
And now I'm getting an error, for some reason, when I try to run the code?
The code is simply a class that uses direct2d to draw on a window.
This is what it looks like:
#pragma once
#include <Windows.h>
#include <d2d1.h>
#include <iostream>
#include "LinkedList.h"
class Graphics
{
private:
ID2D1Factory* pFactory;
ID2D1HwndRenderTarget* pRenderTarget;
ID2D1SolidColorBrush* pBrush;
RECT bounds;
float lineWidth = 5.0f;
LinkedList pointList;
public:
Graphics();
~Graphics();
void BeginDraw() { pRenderTarget->BeginDraw(); };
void EndDraw() { pRenderTarget->EndDraw(); };
void SetBrushColor(float r, float g, float b, float a);
void SetBrushColor(float r, float g, float b);
void SetLineWidth(float width);
RECT GetBounds();
void ClearScreen(float r, float g, float b, float a);
void ClearScreen(float r, float g, float b);
void FillCircle(float x, float y, float radius);
void DrawCircle(float x, float y, float radius);
void FillRect(float x, float y, float w, float h);
void DrawRect(float x, float y, float w, float h);
void MoveTo(float x, float y);
void LineTo(float x, float y);
void tester();
bool Init(HWND* pWindowHandle);
};
And the error I'm getting is this:
Error LNK2019 unresolved external symbol _D2D1CreateFactory#16 referenced in function "long __cdecl D2D1CreateFactory(enum D2D1_FACTORY_TYPE,struct _GUID const &,void * *)" (?D2D1CreateFactory##YAJW4D2D1_FACTORY_TYPE##ABU_GUID##PAPAX#Z) ffff c:\Users\sharkgaming\documents\visual studio 2015\Projects\ffff\ffff\Graphics.obj 1
At first I thought it was because I forgot to link to the d2d1.lib but even after doing that I'm still getting the error?
So, does anyone know why I'm getting the error and how to fix it?
Okay,
after googling around, for an hour or two, I found out that basically adding this:
#pragma comment(lib,"d2d1.lib")
would fix my problem.
But I have absolutely no idea why, since I already went in to the linker settings and added d2d1.lib to the additional library files?
EDIT: OMG I just figured it out.
I added the library to the x64 build settings not the x86. -_-
I was tweaking a bit of GDAL code, and am using a typedef like this
typedef CPLErr (*MYWriter)( double dfLevel, int nPoints, double *padfX, double *padfY, void * );
which is being used in a class like this
class GDALGenerator
{
...blah...
public:
MYWriter pfnWriter;
GDALGenerator( int nWidth, int nHeight, MYWriter pfnWriter, void *pWriterCBData );
...blah...
};
but in the same file, below the GDALGenerator class when I create the function like so
CPLErr MYWriter( double dfLevel, int nPoints, double *padfX, double *padfY, void *pInfo )
{}
I get this error
Error 2 error C2365: 'MYWriter' : redefinition; previous definition
was 'typedef' f:\projects\map\somecpp\somecpp.cpp 1330 MyProjectName
I'm confused, because a standard GDAL function is being used exactly like this, and it works fine (the class is in a separate DLL in that case). I just made a copy of the function with the different name, and it doesn't work.
you cannot use the type name as a function name, only as a type of a variable.
I hope this makes it clear:
CPLErr f( double dfLevel, int nPoints, double *padfX, double *padfY, void *pInfo )
{}
MYWriter foo = f;
``
I have incorporated polymorphism with a single subclass for now. Two of these functions, as seen in the following code, Draw() and SetValue(int,int,int) are causing linker errors.
#include "Header.h"
class Object{
int tag;
public:
void SetValues(int,int,int);
void Draw();
int getTag(){
return tag;
}
};
class Square: public Object{
int red;
int green;
int blue;
void Draw();
void SetValues(int red2,int green2, int blue2){
red=red2;
green=green2;
blue=blue2;
}
};
void Square::Draw(){
// Draws a square with a gradient color at coordinates 0, 10
glBegin(GL_QUADS);
{
glColor3f(red, green, blue);
glVertex2i(1, 11);
glColor3f(red * .8, green * .8, blue * .8);
glVertex2i(-1, 11);
glColor3f(red * .5, green * .5, blue * .5);
glVertex2i(-1, 9);
glColor3f(red * .8, green * .8, blue * .8);
glVertex2i(1, 9);
}
glEnd();
}
The errors
Error 1 error LNK2019: unresolved external symbol "public: void __cdecl Object::SetValues(int,int,int)" (?SetValues#Object##QEAAXHHH#Z) referenced in function "public: void __cdecl State::DrawAll(void)" (?DrawAll#State##QEAAXXZ) C:\Users\Asher\documents\visual studio 2012\Projects\Procedural Terrain\Procedural Terrain\State.obj Procedural Terrain
Error 2 error LNK2019: unresolved external symbol "public: void __cdecl Object::Draw(void)" (?Draw#Object##QEAAXXZ) referenced in function "public: void __cdecl State::DrawAll(void)" (?DrawAll#State##QEAAXXZ) C:\Users\Asher\documents\visual studio 2012\Projects\Procedural Terrain\Procedural Terrain\State.obj Procedural Terrain
In a larger class, which does no inherit Object's functions, uses DrawAll() with a Draw() call in it.
The cpp file and the two respective header files are as follows.
#include "Header.h"
#include "Object.h"
float rotate_z=0;
class State{
private:
std::vector<Object> storage;
public:
State();
State Interpolate(State, State, double);
void Integrate(State,double, const double);
void DrawAll();
void AddObject(Object);
void RemoveObject(int);
};
State::State(){
}
State State::Interpolate(State current,State previous,const double alpha){
//current*alpha + previous * ( 1.0 - alpha );
return current;
}
void State::Integrate(State current, double t, const double dt){
}
void State::AddObject(Object object){
storage.push_back(object);
}
void State::RemoveObject(int tag){
//for(int i=0;i<storage.size;i++){
// if(storage.at(i).getTag==tag){
//storage.erase(storage.begin()+i);
// }
//}
}
void State::DrawAll(void)
{
// reset view matrix
glLoadIdentity();
// move view back a bit
glTranslatef(0, 0, -30);
// apply the current rotation
glRotatef(rotate_z, 0, 0, 1);
rotate_z += 5;
// by repeatedly rotating the view matrix during drawing, the
// squares end up in a circle
int i = 0, squares = 15;
float red = 0, blue = 1;
for (; i < squares; ++i){
Square square;
Object * squareP=□
glRotatef(360.0/squares, 0, 0, 1);
// colors change for each square
red += 1.0/12;
blue -= 1.0/12;
squareP->SetValues(red,0.6,blue);
squareP->Draw();
}
}
The Object header -
#ifndef Object_H
#define Object_H
class Object{
int tag;
public:
void SetValues(int,int,int);
void Draw();
int getTag();
};
class Square: public Object{
int red;
int green;
int blue;
void Draw();
void SetValues(int red2,int green2, int blue2);
};
#endif
Lastly the State header -
#ifndef State_H
#define State_H
#include "Object.h"
#include <vector>
class State{
private:
std::vector<Object> storage;
public:
State();
State Interpolate(State, State, double);
void Integrate(State,double, const double);
void DrawAll();
void AddObject(Object);
void RemoveObject(int);
};
#endif
This is the first C++ project I have worked on and have not fully transferred from a Java background. What could the problem be?
Your Object class has no implementation of SetValues function. You may want a pure virtual function. Same for Draw.
class Object {
virtual void SetValues(int,int,int) = 0;
}
Also note that in C++ functions are not virtual by default. You have to use the virtual keyword explicitly in the base class.
Also class Object seems to be defined at multiple places. Why? Defining it in Object.h would be sufficient.
Also please indent your code because it is very hard to read.
Also std::vector<Object> will not do what you want! Unline Java, where everything is a reference, in C++ things are stored by value in an std::vector and therefore your code is subject to the slicing problem. You want to use at lease a pointer there (std::vector<Object*>) but a smart pointer would be even better (std::vector<std::shared_ptr<Object>>)
Nothing is marked as virtual, and I can't see any implementation for Object::Draw() or Object::SetValues().
In C++ to allow a subclass to override a function in the base class, it needs to be marked as virtual (in Java everything is always "virtual").
You can have "abstract" methods (like Java) by saying
class Object {
public:
virtual void SetValues(int,int,int) = 0;
I'm developing my code using C++ and want to use MPFIT nonlinear curve fitting library, which is developed in C but allows to compile in C++.
For example I have a class named "myClass", and this class has a function myClass::Execute()
I include "mpfit.h" to myClass.h file. And try to call a function called mpfit from Execute().
int status = mpfit(ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);
The problem is ErrorFunction is a function of myClass. So compiler gives error when I try to use this. I tried to carry the ErrorFunction out of the class object, but this time I take the error given below:
Error when the ErrorFunction is outside of the class:
Error 4 error C2664: 'mpfit' : cannot convert parameter 1 from 'int
(__cdecl *)(int,int,double *,double,double *,void *)' to
'mp_func'
Error when the ErrorFunction is inside the class:
Error 3 error C3867: 'myClass::ErrorFunction': function call missing argument list; use '&myClass::ErrorFunction' to
Definition of error function:
int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)
How can I call this function and parse it into mpfit, which is a C function?
mp_func is defined as:
/* Enforce type of fitting function */
typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
int n, /* Number of variables (elts of x) */
double *x, /* I - Parameters */
double *fvec, /* O - function values */
double **dvec, /* O - function derivatives (optional)*/
void *private_data); /* I/O - function private data*/
Make sure that your calling conventions match. C libraries use the C calling convention, or cdecl (__cdecl). If you're using the mp_func typedef within C++, it could be defaulting to the compiler's standard calling convention, or stdcall (__stdcall). Either make a new typedef or change it to the following:
typedef int __cdecl (*mp_func)(int m, /* Number of functions (elts of fvec) */
int n, /* Number of variables (elts of x) */
double *x, /* I - Parameters */
double *fvec, /* O - function values */
double **dvec, /* O - function derivatives (optional)*/
void *private_data); /* I/O - function private data*/
And when you declare ErrorFunction, also declare it as __cdecl:
int __cdecl ErrorFunction(int, int, double*, double *, double **, void *);
If the compiler still complains when calling the mpfit function, you can try casting your function pointer to the mp_func typedef with cdecl:
int status = mpfit((mp_func)ErrorFunction, num1, num2, xsub_1D, 0, 0, (void *) &variables, &result);
Given the definitions of mpfit() and mp_func that you have shown, you would need to use the private_data parameter of mp_func to pass your class's this pointer around. You are currently using that parameter to pass your variables item around instead. Make variables be a member of your class (if it is not already) and then pass this to mpfit() instead:
class MyClass
{
private:
TheDataType variables;
static int ErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
public:
void DoIt();
};
void MyClass::DoIt()
{
// ...
int status = mpfit((mp_func)&ErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result);
// ...
}
int MyClass::ErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
// use pThis->variables as needed ...
}
Or:
class MyClass
{
private:
static int MPFitErrorFunction(int m, int n, double *x, double *fvec, double **dvec, MyClass *pThis);
int MyErrorFunction(int m, int n, double *x, double *fvec, double **dvec);
public:
void DoIt();
};
void MyClass::DoIt()
{
// ...
int status = mpfit((mp_func)&MPFitErrorFunction, num1, num2, xsub_1D, 0, 0, this, &result);
// ...
}
int MyClass::MPFitErrorFunction(int m, int n, double* x, double *fvec, double **dvec, MyClass *pThis)
{
return pThis->MyErrorFunction(m, n, x, fvec, dvec);
}
int MyClass::MyErrorFunction(int m, int n, double* x, double *fvec, double **dvec)
{
// use this->variables as needed ...
}
Looks like instead of:
int ErrorFunction(int dummy1, int dummy2, double* xsub, double diff, double *dvec, void *vars)
it should be:
int ErrorFunction(int dummy1, int dummy2, double* xsub, double *diff, double **dvec, void *vars)
to match your
typedef int (*mp_func)(int m, /* Number of functions (elts of fvec) */
int n, /* Number of variables (elts of x) */
double *x, /* I - Parameters */
double *fvec, /* O - function values */
double **dvec, /* O - function derivatives (optional)*/
void *private_data); /* I/O - function private data*/
Your callback must be declared extern "C" for this to work.
Edit: I see people are having hard time grasping this fact. The standard says (7.5/1):
Two function types with different language linkages are distinct types
even if they are otherwise identical.
There's a standard idiom for C++ - to - C, using the pimpl idiom:
foo_c.h:
#ifdef __cplusplus
extern "C" {
#endif
//forward declaration. clients of foo_c.h should only hold pointers to Foo_c
typedef struct Foo_c Foo_c;
int someMethod(Foo_c* foo);
#ifdef __cplusplus
}
#endif
foo_c.cpp:
#include <foo.h>
struct Foo_c {
Foo foo;
}
int someMethod(Foo_c* foo) {
try {
foo->foo.someMethod();
return 0; //no error
}
catch(...) {
return 1; //error
}
}
(Edited for extern "C"'s per below answer.)
I'm still kind of new to C++ and don't know why I'm getting these linker errors while trying trying to call these functions in another class.
The errors are:
error LNK2019: unresolved external symbol "public: float __thiscall Star::getMass(void)" (?getMass#Star##QAEMXZ) referenced in function "public: void __thiscall Projectile::Update(class Star * const,int)" (?Update#Projectile##QAEXQAVStar##H#Z)
error LNK2019: unresolved external symbol "public: float __thiscall Star::getX(void)" (?getX#Star##QAEMXZ) referenced in function "public: void __thiscall Projectile::Update(class Star * const,int)" (?Update#Projectile##QAEXQAVStar##H#Z)
error LNK2019: unresolved external symbol "public: float __thiscall Star::getY(void)" (?getY#Star##QAEMXZ) referenced in function "public: void __thiscall Projectile::Update(class Star * const,int)" (?Update#Projectile##QAEXQAVStar##H#Z)
Projectile.cpp:
#include <hge.h>
#include "Projectile.h"
#include "Physics.h"
#include "Star.h"
#include <math.h>
Projectile::Projectile(float xV, float yV, float x, float y, float m, HTEXTURE tex)
{
xVel = xV;
yVel = yV;
xPos = x;
yPos = y;
mass = m;
quad.tex = tex;
}
void Projectile::Update(Star stars[], int length)
{
for(int i = 0; i<length; ++i)
{
float force = Physics::calcGravityForce(mass, stars[i].getMass(), Physics::calcDist(xPos, yPos, stars[i].getX(), stars[i].getY()));
Accelerate(force, stars[i].getX() - xPos, stars[i].getY() - yPos);
}
}
void Projectile::Accelerate(float force, float x, float y)
{
float c = sqrt((x * x) + (y * y));
xVel += x/c;
yVel += y/c;
}
Star is defined in Star.h here:
#ifndef STAR_H
#define STAR_H
#include <hge.h>
class Star
{
private:
float mass, radius, x, y;
hgeQuad quad;
public:
Star(float m, float r, float X, float Y, HTEXTURE);
float getMass();
float getRadius();
float getX();
float getY();
Star() {}
};
#endif
You have several functions declared in the Star class:
Star(float m, float r, float X, float Y, HTEXTURE);
float getMass();
float getRadius();
float getX();
float getY();
And you are trying to use some of them without providing a definition, that is to say, the body of the function, which is why you're getting those linker errors.
Add a new .cpp file to your project named Star.cpp (the name doesn't matter though) and add the definitions of the functions for the Star class, like you've done for the Projectile class. (You could just add them to any .cpp file in your project, like Projectile.cpp, but if you have a separate header file, it's good to have a seperate .cpp file too.)
Or if you don't want to have another cpp file in your project, you can put the bodies of the functions inside the class itself:
class Star
{
private:
float mass, radius, x, y;
hgeQuad quad;
public:
Star(float m, float r, float X, float Y, HTEXTURE);
float getMass() { return mass; }
float getRadius() { return radius; }
float getX() { return x; }
float getY() { return y; }
Star() {}
};
That style is common for small "getter" functions like getMass, getRadius, etc. which just return a member variable.
Though it's not directly related to your question, I should point out a few things:
Make all your "getter" functions (like getMass etc) const (so that they can be used on const Star objects) by putting the word const after the parameters (the () in this case) like this: float getMass() const { return mass; }
Because you have member variables in the Star class, you should set them to some sensible default value in the constructor which takes no parameters,
like this:
Star() : mass(0), radius(0), x(0), y(0) {}
Which will set mass, radius, x and y to 0. (This unusual syntax is called an initialiser list. You can read about them here.)
You can even do this without a seperate constructor by using default arguments:
Star(float m = 0, float r = 0, float X = 0, float Y = 0, HTEXTURE = 0);