C++ - "Unspecialised class template" error with shared_ptr - c++

I have a class Room and it holds a vector of shared_ptrs to Option objects like so:
private:
vector<shared_ptr<Option> > options;
But for some reason when I build, I get the following errors:
'shared_ptr' : unspecialized class template can't be used as a template argument for template parameter '_Ty', expected a real type
'std::tr1::shared_ptr' : use of class template requires template argument list
Strangely, I also have a vector of shared_ptrs, exact same syntax but there's no problem with that one.
There's also a bunch of places that bring up the error "'Option': undeclared identifier", which brings me to think it might be a problem with the Option class, but it seems to be fine. Here's the code for Option:
Option.h:
#pragma once
#include "Room.h"
#include <memory>
using namespace std;
class Option
{
protected:
int id;
char* text;
public:
Option(void);
Option(int, char*);
virtual ~Option(void);
char* getText();
int getID();
};
Option.cpp:
#include "Option.h"
#include "Room.h"
#include <memory>
using namespace std;
Option::Option(void)
{
}
Option::Option(int newID, char* newText){
id = newID;
text = newText;
}
Option::~Option(void)
{
}
char* Option::getText(){
return text;
}
int Option::getID(){
return id;
}

There is a bit of conjecture in this answer since you haven't posted the code for the Room class. I'm assuming this code
private:
vector<shared_ptr<Option> > options;
is in Room.h. Your Option.h file includes Room.h, hence the Room class gets declared before the Option class. So Option is an incomplete type when the Room class' destructor is compiled and the shared_ptr implementation tries to delete the Option object.
From the code above, I don't see why Option.h needs to include Room.h, in fact, it should be the other way around. If it does indeed need to include the file, you should be able to work around the problem by explicitly declaring Room::~Room() out-of-line in Room.cpp.
EDIT:
Turns out ~shared_ptr<T> does not require T to be a complete type. However, shared_ptr<T>( T* ) and shared_ptr<T>::reset( T* ) do, and the problem may be because some operation on the vector is invoking a call to one of these (more likely the former).

vector<shared_ptr<Option >>
You almost did that right :)
vector<shared_ptr<Option> >
It's the two > characters that, when touching, cause the strange errors you see. It is being interpreted as the >> operator.
BTW, thank you for posting your code exactly as it is rather than typing it back in and possibly hiding the mistake.

Related

Opaque struct in C++ as class member

I have not been able to find an answer on this, but my case is:
// vulkan_glfw_backend.hpp
struct alignas(8) VulkanGlfwWindowContext;
class MY_API VulkanGlfwBackend
{
// [...]
private:
VulkanGlfwWindowContext* mpContext;
};
And the source file, where I want to have the implementation:
// vulkan_glfw_backend.cpp
#include "vulkan_glfw_backend.hpp"
struct VulkanGlfwWindowContext
{
int numWindows;
GLFWwindow* windows[MAX_WINDOWS];
};
Initially, my compiler complained because it couldn't determine the alignment requirements for the class, which I suppose makes sense. Then I added the alignas attribute. But now I get an error message, which I cannot understand the logical reason for:
vulkan_glfw_backend.cpp:113:51: error: invalid use of incomplete type ‘struct VulkanGlfwWindowContext’
113 | for (int i = 0; i < mpContext->numWindows; i++)
Since I declare it explicitly as a pointer inside a class, the storage requirements should be clear. Additionally, it's an implementation detail how the memory layout of the struct looks, which the compiler knows at compile-time, because it is defined at the top of the source file.
So, why is this going wrong, and can I fix it somehow? For several reasons I desire to have an opaque type. Thanks!
Answering my own question :)
So this is one of those days, where I'm not completely posting the entire code as is (my apologies!). So, the entire thing is inside a namespace:
// header
namespace mynamespace
{
// vulkan_glfw_backend.hpp
struct alignas(8) VulkanGlfwWindowContext;
}
//source
#include "vulkan_glfw_backend.hpp"
using namespace mynamespace;
struct VulkanGlfwWindowContext
{
int numWindows;
GLFWwindow* windows[MAX_WINDOWS];
};
The reason for this going wrong - again, I don't understand the logics behind it. Anyways, this is the fix:
//source
struct mynamespace::VulkanGlfwWindowContext
{
int numWindows;
GLFWwindow* windows;
};
Apparently, C++ doesn't understand the definition without fully-qualified namespace prepended to the name. I have seen the same issue with functions - it is not enough to open the namespace, it must be included in the definition.
This confuses me, as it is not required when implementing class member functions, where the name of the class is sufficient, e.g. someclass::somemember() {}.
But it works now!

Why separating template definition/declaration sometimes work

I'm wide awake at 1AM trying to figure out a compilation error I'm having.
I can't really write the exact code but I'll do my best to make my question clear.
ClassWithTemplateFunction.hpp
#include "StructA.hpp"
#include "ClassB.hpp"
class ClassWithTemplateFunction
{
template<typename A>
void MyTemplateFunc();
}
ClassWithTemplateFunction.cpp
template<typename T>
void ClassWithTemplateFunction::MyTemplateFunc()
{
// code block
}
StructA.hpp
struct ClassWithTemplateFunction;
struct StructA
{
void StructAFunc(ClassWithTemplateFunction* templ);
}
StructA.cpp
#include "ClassWithTemplateFunction.hpp"
#include "StructA.hpp"
StructA::StructAFunc(ClassWithTemplateFunction* templ)
{
templ->MyTemplateFunc<SomeTemplate>();
}
The above codes work great. "SomeTemplate" is also another class. But then I added a new class which also uses the template function:
ClassB.hpp
class ClassWithTemplateFunction;
class ClassB
{
void ClassBFunc();
}
ClassB.cpp
#include "ClassB.hpp"
#include "ClassWithTemplateFunction.hpp"
void ClassB::ClassBFunc(ClassWithTemplateFunction* templ)
{
templ->MyTemplateFunc<SomeTemplate>();
}
And for some reason, this now introduced a linker error (undefined reference to MyTemplateFunc()). I can't figure out why it suddenly produced this issue. Obviously it can be fixed by moving the definition to the header file, but I want to understand, before adding ClassB, the code works just fine.
If ClassWithTemplateFunction.cpp instantiates MyTemplateFunc with some template arguments somehow (e.g. by calling it), you'll be able to use MyTemplateFunc with the exact same arguments anywhere in the program.
That's why you don't get an undefined reference in the first case.
But it's not possible for an invocation of MyTemplateFunc with the exact same template arguments in a different file to cause an undefined reference. Please check if the template argument is really the same in both cases.

Visual studio unable to resolve overloaded unambiguous function in class and namespace

See code below
#include <iostream>
#include <string>
namespace stringhelper
{
std::string to_string(int n) { return "0"; } // ignore wrong implementation. simplified for example purpose
}
using stringhelper::to_string;
class TestClass
{
public:
std::string to_string() const { return "TestClass:" + to_string(m_value); }
private:
int m_value;
};
int main()
{
TestClass tc;
std::cout << tc.to_string();
}
If TestClass does not implement function to_string(), within TestClass, it is able to resolve to_string(m_value) to stringhelper::to_string(int). However, the moment TestClass implements function to_string(), the compiler is unable to resolve to_string(int) to stringhelper::to_string.
Rather, it insists/resolves the function to TestClass::to_string and gave an error that the function TestClass::to_string does not take in 1 arguments.
Why is this so?
Environment:
Visual Studio 2008 Professional Edition 9.0.21022.8 RTM
Configuration: Win32
Windows 8
This behavior is not limited to Visual Studio 2008. If tested in modern Clang implementations you will see the same behaviour. As you may know, functions in derived classes which don't override functions in base classes but which have the same name will hide other functions of the same name in the base class.
The "problem" here is that you, by using the using statement introduces a function named to_string into a scope that is essentially a victim of the exact same thing as what happens in the above example, when looking at it from inside your class.
If the standard had you call member functions with this->foo() this would probably not have been an issue. But since function calls within a class are presumed to be part of the class and only if not found looked for in other scopes this becomes an issue.
Since you have an implementation in your class, that has priority and will be used. Since you want a version that takes an int as an argument, an overloaded version of your member function will be looked for and since it does not exist you get the error you see.
This is part of why using namespace can often introduce errors that might be unintuitive to understand. If you want to make sure you use the stringhelper::to_string implementation while you are in a class with a function that has the same name you have to be explicit.
This would work fine for instance, even if you keep your using statement.
#include <iostream>
#include <string>
namespace stringhelper
{
std::string to_string(int n) { return "0"; } // ignore wrong implementation. simplified for example purpose
}
using stringhelper::to_string;
class TestClass
{
public:
std::string to_string() const { return "TestClass:" + stringhelper::to_string(m_value); }
private:
int m_value;
};
int main()
{
TestClass tc;
std::cout << tc.to_string();
}

This declaration has no storage class or type specifier in C++

I have multiple classes in my program.
A) When I create an object of a class in another class I am getting no error but when I use the object to call a function I get the above error.
B)Also if I create an object of another class and call a function using that in the constructor of my class then I get no error like this.
C) Cout function does not work in the body of the class except when I put it any function
D) The main class is able to do all of these and I am not getting any error.
It would be great to hear back soon. Thank you in advance.
Following is the code : These are two classes in my cpp. I am facing no problems except using object after creating it. the code is too huge too be posted. Everything can be done in main but not in other classes why?
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
#include <vector>
#include <map>
using namespace std;
class Message
{
public:
void check(string side)
{
if(side!="B"&&side!="S")
{
cout<<"Side should be either Buy (B) or Sell (S)"<<endl;;
}
}
};
class Orderbook
{
public:
string side;
Orderbook() //No Error if I define inside constructor
Message m; //No Error while declaring
m.check(side); //Error when I write m. or m->
};
This is a mistake:
m.check(side);
That code has to go inside a function.
Your class definition can only contain declarations and functions.
Classes don't "run", they provide a blueprint for how to make an object.
The line Message m; means that an Orderbook will contain Message called m, if you later create an Orderbook.
Calling m.check(side), meaning you are running actual code, but you can't run code outside main() - you can only define variables.
In C++, code can only appear inside function bodies or in variable initializes.
You can declare an object of a class in another Class,that's possible but you cant initialize that object. For that you need to do something like this :-->
(inside main)
Orderbook o1;
o1.m.check(side)
but that would be unnecessary. Keeping things short :-
You can't call functions inside a Class

Error: no instance of overloaded function, in constructor (C++)

I have a very weird problem... First of all, here are my class's files:
Show.h:
#ifndef SHOW
#define SHOW
#include <iostream>
#include <string>
#include <string.h>
class Show
{
private:
std::string m_time;
int m_serial
public:
Show(const std::string &time, const int &serial);
~Show();
};
#endif
Show.c:
#include "Show.h"
Show::Show(const std::string &time,const int &serial)
{
}
As you can probably see, I only wrote the declaration of the constructor, when the visual studio underlined the second "Show" word in the Show.c file, and told me:
"void Show::Show(const std::string &time,const int &serial)
Show::Show()
Show::Show(const Show &)
Error: no instance of overloaded function "Show::Show" matches the specific type"
And when I stand with the mouse cursor over the constructor function in the Show.h file it looks like that function doesn't exists... I have written some classes in c++ before, and that is the first time anything like that happens to me... help please :(
You forgot to put ; after m_serial field variable. I believe this is the reason of the problem you have. Unfortunately many compilers do not give the exact reason of the problems like this, so you have to be careful with syntax rules.