I encountered a weird error when modifying my class structures, which I couldn't reproduce with simpler classes.
Situation:
I have decided to have a class Input have a reference (a plain old pointer) to the object to be manipulated by the user's key input, Camera. Previously I linked them via Input's constructor: Input in(&cam); but after including a templated member in Camera: Buffer<Layout> buffer my whole main function went berserk.
Previously this was fine:
Camera cam();
Input in(&cam);
cam.setProj(glm::mat4(1.0f)); // Example of function call
The headers are of course in separate files, and the implementations in .cpp-files.
Input has a member Camera *cam and the constructor for Input is:
Input::Input(Camera *camera){
this->cam = camera;
}
Problem:
It no longer is fine. The error message is:
Input::Input(Input &&): cannot convert argument 1 from
'Camera(__cdecl *)(void)' to 'Camera *'
Additionally, every attempt to call Camera's functions gives two additional errors: expression must have class type and left of '.func' must have class/struct/union.
Attempt to create a minimal example:
Tl;dr: didn't quite get there. Or at least the issue isn't directly in taking the address of a class with a template member. The following code works.
#include <stdio.h>
#include <stdlib.h>
template <typename T>
class Member{
public:
Member(T variable):var(variable){};
T var;
};
class Owner{
public:
Owner(int m):member(m){};
Member<int> member;
};
class Referencer{
public:
Referencer(Owner *o){this->op = o;};
Owner *op;
};
int main(){
Owner o(1);
Referencer r(&o);
printf("%d\n", r.op->member); // Output is 1.
return 0;
}
As the above example works, I'm not sure whether it actually affects the situation to have a template member. I'm really lost with this one. Any help is greatly appreciated!
Camera cam();
It is a simple function declaration. You declare a function returning Camera and accepting zero arguments. And your MSVC compiler complains about it!
Input::Input(Input &&): cannot convert argument 1 from 'Camera(__cdecl *)(void)' to 'Camera *'
Just use:
Camera cam;
and let the default constructor to be called.
Related
I have a templated class and with in that class a further templated method. The templated method requires a different non-explicit but standard typename as shown in the Class and method declaration below.
template <typename T>
class Matrix
{
public:
// constructors
Matrix(int rows, int cols,T _initial);
Matrix():mCols(0),mRows(0),mdata(0)
{ }
Matrix(int rows,int cols,
std::vector<T>&X):mRows(rows),mCols(cols),mdata(X)
{ }
int get_numofrows(); // returns mRows
int get_numofcols() // returns mCols
void show_matrix(); // prints matrix on console, which is really the vector <T> mdata
template<typename E> // <----focus is here
Matrix<E> convert_Matrix(); // <----and here
// other methods not relevant to this problem go here
// ....
private:
int mRows;
int mCols;
std::vector<T> mdata;
};
the implementation details of method convert_Matrix() is shown below:
template<T>
template<E>
Matrix<E> Matrix<T>::convert_Matrix()
{
// creates a vector cast of all elements of underlying
// vector of type T to vector elements of type E
// eg; vector<E> D uses vector copy constructor
std::vector<E> D(this->mdata.begin(), this->mdata.end());
// uses vector D as an argument to create the rest of the matrix
Matrix<E> MX(this->get_numofrows(),this->get_numofcols(),D);
return MX;
}
Intuitively it would seem that the instances in main that use this method (convert_Matrix()) should compile and link but complains of substitution/deduction errors on E only when the convert_Matrix() method is invoked by an instance. It compiles without incident if the method instance is not called in main.
The following code was was developed to test the method convert_Matrix():
#include " Matrix.h"
int main()
{
std::vector<float> Mz = {
139.342, 144.167,149.543,153.678,155.987,155.21,155.23,155.876,
144.112,151.34,153.6789,156.34,159.0124,156.678,156.56,156.6543,
150.456,155.123,160.45,163.876,158.432,156.78,156.123,156.525,
159.567,161.267,162.567,160.67,160.59,159.001,159.675,159.456,
159.876,160.743,161.456,162.432,162.876,155.543,155.123,155.840,
161.111,161.222,161.333,161.678,160.543,157.890,157.1212,157.987,
162.111,162.222,161.333,163.987,162.888,157.543,157.666,157.345,
162.234,162.777,161.888,161.444,163.99,158.775,158.234,158.98
};
Matrix<float> FF(8,8,Mz);
// Matrix<int>BV = FF.convert_Matrix(); <--deduction/substitution error couldn't deduce E
Matrix<int>BV = FF.convert_Matrix<int>();// <---works
BV.show_Matrix();
FF.show_Matrix();
}
I was successful in getting the code above to compile and execute with an instance instantiation of FF.convert_Matrix as shown above but I am not sure if this approach and definition is syntactically accurate. I tried many more type conversions and they all seemed to compile and link and execute correctly without incident (substituting the appropriate type in place of int)
which leads me to the following questions
1) I can understand from a logical perspective, that if the compiler linker complains about type deduction I should try to help it. I tried auto, I tried decltype,
I tried combinations of both, why did the approach I used work? And why didn't the straight forward approach (e.g. class declaration) not work?
2) I stumbled upon this solution illustrated above, by trial and error. Is there some sort of rule in the ISO standard that defines what I did?
3) Is there a better way to do the same thing? Why is the method signature in the class definition, different signature then when it is instantiated in an instance?
4) I do not think this solution issue is best served by a specialization and more code. The solution I stumbled upon works, so why add more code?
I would rather just change the minimum in class declaration and implementation semantics for clarity
Any comments you have or alternate solutions will be greatly appreciated.
The compiler does not look at the type on the left side of an assignment to deduce template parameters. What the compiler sees is FF.convert_Matrix(), and it is unable to deduce the template parameter for convert_Matrix. This is why you need to explicitly specify the template parameter.
The standard library's std::get, when used to extract a value from a tuple based on type, also needs to have the type explicitly specified.
I know there is a lot of these "cannot convert argument" questions here, but I promise I looked around a lot and I think my particular case hasn't been asked yet, plus I have tried debugging this for quite a few hours but can't seem to get it.
Basically, I am creating a Component system for a 2D game engine. I have separated my logic into two parts: Component and ComponentSystem. The Component class will store only data, while the ComponentSystem will update and manipulate that data accordingly.
The ComponentSystem base class is abstract with a template to specify which Component the system will be using. Here is the .h file:
// =================================================================================================
// == COMPONENT SYSTEM CLASS =======================================================================
// =================================================================================================
template <class T>
class ComponentSystem
{
public:
// -- ctor & dtor
ComponentSystem<T>();
~ComponentSystem<T>();
// -- update components
virtual void UpdateComponents(float dt) = 0;
// -- populates the components of this systems
virtual void PopulateFromCurrentLevel() = 0;
// -- clears the components of this system
virtual void ClearFromCurrentLevel() = 0;
protected:
// -- actual list of components
std::vector<T*> components;
};
I then also have a SpriteComponentSystem, which derives from ComponentSystem, but with the SpriteComponent as the template type:
class SpriteComponentSystem : public ComponentSystem<SpriteComponent>
{
public:
SpriteComponentSystem();
~SpriteComponentSystem();
virtual void UpdateComponents(float dt);
virtual void PopulateFromCurrentLevel();
virtual void ClearFromCurrentLevel();
};
Finally, in my Game class I am storing a vector of the base class, like so:
std::vector<ComponentSystem<Component*>*> systems;
However, when I try to push a SpriteComponentSystem* into systems, I get the following error:
C2664 - 'void std::vector<HSZGame::ComponentSystem<HSZGame::Component *>
*,std::allocator<_Ty> >::push_back(_Ty &&)': cannot convert argument 1 from
'HSZGame::SpriteComponentSystem *' to
'HSZGame::ComponentSystem<HSZGame::Component *> *const &'
I have tried implementing a specific cast from one object to the other, and also tried doing a dynamic_cast which worked for compile time but the object was then nullptrat runtime.
In case anyone is wondering, SpriteComponent does indeed inherit from Component, which is the base class. Thanks again for your help everyone!
First of all you are initializing a std::vector<ComponentSystem<Component*>*> that takes a ComponentSystem with a Component* template parameter. This means that your vector components that is contained within ComponentSystem is holding a pointer to a pointer to a Component. This might be an error on your part unless you actually mean to hold a pointer to a pointer. If you don't your vector should be initialized std::vector<ComponentSystem<Component>*>.
Secondly it seems you would like to use runtime polymorphism so that your vector systems can hold not only ComponentSystem<Component> objects but also SpriteComponentSystem (AKA ComponentSystem<SpriteComponent> objects).
Unfortunately the language does not allow this since templates are instantiated at compile time and each instantiation is its own type. The language views ComponentSystem<Component> and ComponentSystem<SpriteComponent> as separate types and hence the compiler is complaining.
I think you would need to rethink this design philosophy.
I'm trying to create a new object of the class Queue<T>, with the following:
Queue<char[40]> *q = new Queue<char[40]>(100);
Then, I want to use this q on another class constructor:
Interface<char[40]> i(q);
If I just use it, I get an error saying invalid conversion from ‘Queue<char [40]>*’ to ‘int’, which I figure means I'm trying to pass the value of q, which is the pointer to it instead of the actual value. Fine. Then I redefined the Interface<T> constructor to receive a pointer instead of the value itself, so the signature is
Interface(DataStructure<T>& q);
Since Queue extends DataStructure. For some reason, now the instantiation of q fails:
undefined reference to `Queue<char [40]>::Queue(int)
But I am quite sure I have written the constructor method WITH an INT parameter
template<typename T>
Queue<T>::Queue(int size): DataStructure<T>(size) {
std::cout << size << std::endl;
}
Why the hell am I getting this error, then? To play with pointers is just getting a mess and I could not figure out by any means what to do now.
This code Queue<T>::Queue(int size) suggests you put the definition in a source file. If you use templates all your code must be in the header file. (There are other approaches, but this is the easiest).
I was working on a project and, while playing around with the code, I came across the following peculiar occurrence.
I have two classes. The first holds three floats in an array representing Cartesian coordinates and defines a method to get those points;
class foo
{
protected:
float m_Coordinates[3];
public:
foo(float coordinates[3]);
void GetPoints(int resultArray[]);
};
foo::foo(int coordinates[3])
{
std::copy(coordinates, coordinates+3, m_Coordinates);
}
void foo::GetPoints(float resultArray[])
{
std::copy(m_Coordinates, m_Coordinates+3, resultArray);
}
The second class also stores an array of floats, but its constructor uses foo as a wrapper class to pass the values:
class bar
{
protected:
float m_MoreCoordinates[3];
public:
bar(foo f);
};
bar::bar(foo f)
{
f.GetPoints(m_MoreCoordinates);
//m_MoreCoordinates is passed by reference, so the values in
//m_MoreCoordinates are equal to the values in f.m_Coordinates
//after this line executes
}
Please ignore the fact that the approach I've taken to this code is simply horrible. It started out as an experiment in using arrays. Passing them as arguments, getting them as return types etc.
OK. Here's where I noticed something strange. If I declare an array of floats and pass them as an argument to bar's constructor, the compiler will generate an instance of class foo and pass that to bar for me. See example code below:
int main(int argv, char** argc)
{
float coordinates[] = {1.0f, 2.1f, 3.0f};
//Here the compiler creates an instance of class foo and passes
//coordinates as the argument to the constructor. It then passes
//the resulting class to bar's constructor.
bar* b = new bar(coordinates);
//Effectively, the compiler turns the previous line into
//bar* b = new bar(foo(coordinates));
return 0;
}
When I saw this, I thought it was a pretty neat feature of the code and was wondering how and why it happened. Is it safe to do this? I don't understand how it works, and so I don't want to depend on it. If someone could explain how this works, I'd really appreciate it.
Edit:
Thanks to Mankarse for pointing out how the conversion would be performed in the main. Initially, I had:
//Effectively, the compiler turns the previous line into
//bar* b = new bar(*(new foo(coordinates)));
As you guessed, compiler is implicitly creating a foo object and passing it to bar. Generally, this is considered a bit dangerous as the foo gets constructed without knowledge, to avoid this you can declare foos constructor as explicit. In that case compiler will not implicitly create foo from array of floats and you will get an compiler error.
When you think about it, you use this all of the time. Consider the following:
void foo(std::string argument);
Then, suppose you invoke this function using a string literal:
foo("argument");
this is the same as:
std::string argument("argument");
foo(argument);
It's a pretty useful feature.
I'm trying to do a base template class which parameter T must be a structure.
When I use a variable declared as being of type T (both in the template class as in a class that extends it defining T) GCC fails to compile it:
GCC error: invalid use of incomplete
type ‘struct x'
Despite it working on VC I understand that it doesn't work because it shouldn't because the compiler isn't aware per the standard of the types that T represent.
Is there a way of making explicit that the type must be a structure?
What I'm doing in the code that works in VC is:
In the base class:
T* x
new T
sizeof(T)
In those that extend it:
x->member
Edit: I tried to take the relevant code. Here it is:
struct SomeStructureType
{
int memberA;
int memberB;
}
template <typename T> class Base
{
protected:
T* s;
void addMember(string name,void* offset);
Base()
{
s = new T;
}
};
class Extender : public Base<SomeStructureType>
{
public:
Extender()
{
addMember("memberA",&s->memberA);
}
}
Most (if not all) times the compiler complains about using an 'incomplete' type the problem resides in trying to use a forward declared class that has not been completely defined.
There are just so many things you can do with an incomplete type: define functions that take or return the type or references to it, define reference or pointer variables of that type... and others you cannot do: define variables of that type, create an object of the type, call any method or request any attribute from the type...
The question in the title can be dismissed; C++ classes and structures cannot be distinguished other than by source code inspection.
The explanation is quite confusing. There's apparently a message about struct x yet the example code contains not a single x. That tells me that you're not careful about matching up errors and source code. Once you do that, you often don't need StackOverflow anymore - you'll see the problem yourself.
There is nothing wrong with the code you've posted other than two missing semicolons after class/struct definitions: http://codepad.org/yfbHa8sO
The problem isn't related to the fact that T must be a structure. The problem is in that one of the structures (that I'm using in my code but was not created by me) is said to be incomplete by gcc. Anyway, I removed the class that uses this structure and other classes compile with the same base class. So, is up to me to fix it and what I assumed about the problem was wrong.