For the upcoming Coursework in January, I started developing a small DirectX engine. To find out if there is a performance increase I wanted to try to not use any virtuals at all (I know that virtuals aren't all bad, but I just wanted to see if it is possible without them).
When I started playing around with a simple StateManager, it got hard to avoid virtuals, but this is my current approach:
#include <boost\function.hpp>
#include <boost\bind.hpp>
template <class Derived>
struct TBaseState {
bool update(float delta) {
return static_cast<Derived *>(this)->update(delta);
};
};
struct CTestState : TBaseState<CTestState> {
bool update(float delta) {
return true;
}
};
class StateManager
{
public:
template <class StateClass> static void setState(StateClass nextState)
{
m_funcptrUpdate = boost::bind(&TBaseState<StateClass>::update, boost::ref(nextState), _1);
}
static bool update(float delta)
{
return m_funcptrUpdate(delta);
}
protected:
private:
static boost::function<bool (float)> m_funcptrUpdate;
};
Visual Studio 2010's Intellisense seems to think everything is fine, but when I want to compile the program and test the StateManager with a very basic approach:
CTestState* t = new CTestState();
StateManager::setState(*t);
StateManager::update(0.0f);
The following error is thrown during linking phase:
error LNK2001: unresolved external symbol "private: static class boost::function<bool __cdecl(float)> StateManager::m_funcptrUpdate" (?m_funcptrUpdate#StateManager##0V?$function#$$A6A_NM#Z#boost##A)
So obviously he can't find the binded function, but how can I solve this issue? I get similar errors if I use boost::bind directly to some class. Since I am a computer science student I would also be interested in some insight or approaches without boost (e.g. bind1st, ...).
EDIT:
I was also thinking about using C++11 Variadic Templates, but one of the coursework requirements is to stick to VS2012.
Static class members need to be given storage. They're like extern variables. Add a definition to one of your .cpp files, outside of the class definition:
boost::function<bool (float)> StateManager::m_funcptrUpdate;
Also, in this code:
template <class StateClass> static void setState(StateClass nextState)
{
m_funcptrUpdate = boost::bind(&TBaseState<StateClass>::update,
boost::ref(nextState), _1);
}
You're maintaining storing a reference to the local variable nextState. That reference will be invalid after setState returns.
Related
I am new to C++ but not to programming. I'm developing a plugin and learning the language at the same time. The plugin is for old software but still being used, so I'm using VS2015 and an SDK to match. I'm having a problem that I just don't know enough to solve but I know that it's the result of something that I'm doing wrong or don't understand. Please also consider that I'm using a third party SDK, with only .H/.HPP files and an occasional .CPP, but that's it. Everything else is wrapped in their libraries. Therefore, I don't have the liberty to change any behavior.
My code snippets are parts of their headers (can't change) and the .cpp is my modified sample code that comes along with their SDK and which I'm using as my base. It is also the area of code that causes the link error. Their samples all work, I can compile them and run them no problem. My code also works and is doing what I want. Things only break when I use my modified code. The reason I'm doing this is because I need access to the message passed into the plugin and can't find any other way to get it other than to try and override "PluginMain". The original sample code actually does call into PluginSetup.cpp because it runs other code within it as setup prior to continuing on. I've only posted the part of my code which is my attempt to override the function as I mentioned and I just included the variable declaration that causes the error. If I comment my variable declaration and other code related to it, program compiles and works again. If I move the variable declaration to another .cpp file in my codebase, code compiles no problem. It just don't like being in PluginSetup.cpp but part from maybe the main.cpp file (which I can't do anything with), PluginSetup.cpp is the first that gets called. So this is where I chose to put my override.
Am I using the friend function correctly? As you can see from the codebase, they've made the ctor as well as the friend function private.
This may also go hand in hand with a question I asked before on how to instantiate a class from this implementation using private friend function and ctors?
Hopefully, what I've posted is enough to give someone all that's needed to figure out what the problem might be.
ns1ns2Main.h
namespace ns1
{
namespace ns2
{
class Plugin;
...
}
}
extern "C" __declspec(dllexport) __MainError PluginMain(const char* caller_, const char* selector_, void* message_);
ns1ns2Plugin.h
#include "ns1ns2Main.h"
namespace ns1
{
namespace ns2
{
class Plugin
{
Public:
static Plugin* const instance();
private:
friend __MainError (::PluginMain) (const char*, const char*, void*);
Plugin();
Plugin(const Plugin&);
virtual ~Plugin();
};
}
}
PluginSetup.cpp
#include "ns1ns2Main.h"
#include "ns1ns2Plugin.h"
//-> My Modification Begins
__MainError (::PluginMain) (const char* caller, const char* selector, void* message)
{
ns1::ns2::Plugin plugin;
if (!plugin.instance())
{
plugin = ns1::ns2::Plugin();
}
if (strcmp(caller, kSPInterfaceCaller) == 0)
{
if (strcmp(selector, kSPInterfaceStartupSelector) == 0)
{
bool bStatus = ns1::ns2::pluginSetup(&plugin);
if (bStatus)
{
plugin_ = clpcsx::Plugin::instance();
plugin_->startup();
}
}
else if (strcmp(selector, kSPInterfaceShutdownSelector) == 0)
{
plugin_ = clpcsx::Plugin::instance();
plugin_->shutdown();
}
}
return error;
}
//<- My Modification Ends
namespace ns1
{
namespace ns2
{
void pluginLoaded()
{
// no-op
}
bool pluginSetup(Plugin* const plugin)
{
clpcsx::Plugin::create(plugin);
plugin->setStartupCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, startup));
plugin->setPostStartupCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, postStartup));
plugin->setPreShutdownCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, preShutdown));
plugin->setShutdownCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, shutdown));
return true;
}
void pluginDestroy(Plugin* const plugin)
{
clpcsx::Plugin::destroy();
}
}
}
Link Error
1>PluginSetup.obj : error LNK2019: unresolved external symbol "private: __cdecl ns1::ns2::Plugin::Plugin(void)" (??0Plugin#ns2#ns1##AEAA#XZ) referenced in function PluginMain
You have to tell the linker to include the libraries. Since this is VS you can add to the main .cpp file
#pragma comment(lib, "xxxx.lib")
where 'xxxx.lib' is the name of the library that has those ns functions. You need to make sure they are in the VS linker path too
I have a project with quite a lot of function templates that I wrote back in Visual Studio 2017, and it always worked fine. Now I have to build it in VS2019, because I need to include the lib in another project that is written in VS2019, and the thing won't build.
There is one function template it seems to take issue with, although it doesn't actually complain about the function itself. The compiler just says "identifier not found" when I invoke it in the code. The thing is there in the namespace, however, even InteliSense sees it and links to it without complaining. Just the compiler won't.
Here's the code in question:
// declaration
namespace Oparse
{
// lots of other functions, many of them templates
template <typename T> OpModel<T> *_ModelPtr(T *receiver) { return new OpModel<T>(receiver); };
}
// Invocation
namespace Oparse
{
template <class T, class U>
class OpModelFactory
: public OpNestable
{
public:
OpModelFactory<T, U>(vector<U*> &receiver) : OpNestable(OP_MODELFACTORY), receiver(receiver) {};
// other stuff
void Serialize(string key, stringstream &stream, unsigned int indents)
{
for (unsigned int i = 0; i < receiver.size(); ++i)
{
// check if the instances are really of the type of this OpModel, otherwise there may be duplicates between polymorphic factories populating the same receiver.
T *currentModel = dynamic_cast<T*>(receiver[i]);
if (currentModel != NULL)
{
OpModel<T> *parser = _ModelPtr<T>(currentModel); // <-- identifier not found
parser->Serialize(key, stream, indents);
delete parser;
}
}
};
private:
vector<U*> &receiver;
}
}
If I comment that invocation, the project builds, despite there being a whole lot more function templates declared right where this one is. I have no clue what to do to make the linker find it. Are there any Visual Studio wizzards who could give me a hint? I must honestly confess that I haven't used the IDE in years, and it's my first time in Visual Studio 2019...
Here's the complete output of the error. There's a second message to it, but I found it perfectly unhelpful:
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(138,27): error C3861: '_ModelPtr': identifier not found
1>D:\Orbiter_installs\Orbiter2016\Orbitersdk\Oparse\include\OpModel.h(152): message : see reference to class template instantiation 'Oparse::OpModelFactory<T,U>' being compiled
And no, there's not further message attached. I have seen similar messages that usually go on with "with ... $further information", but this is all I get.
There is a circular dependency problem.
In Oparse.h, you first include OpModel.h that requires_ModelPtr in implementation of Serialize , but_ModelPtr is only defined later in the header.
You need to forward declare the template method.
In OpModel.h, write this instead:
namespace Oparse
{
template<typename T> class OpModel;
template <typename T> OpModel<T>* _ModelPtr(T* receiver);
// Remaining of OpModel.h...
typedef map<string, pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpModelDef;
typedef vector<pair<Oparse::OpValue*, vector<Oparse::OpValidator*>>> OpValues;
...
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.
I've been trying to come up with a means of generating a C interface for a C++17 project of mine. The project produces an executable that loads plugins on the fly. I played with clang for a while before discovering SWIG, and I'm wondering if SWIG is up to the task, or if there's a trivial amount of work that I can do to make it suitable for this scenario.
Here's my vision of the plugin interface. Suppose the source code of my program looks like this:
header.h
namespace Test {
struct TestStruct {
int Data;
};
class TestClass {
public:
virtual ~TestClass() = default;
void TestMethod(TestStruct&) const;
virtual void TestVirtual(int);
};
}
then the following code should be generated:
api.h
// opaque structs
typedef struct {} Test_TestStruct;
typedef struct {} Test_TestClass;
typedef struct {
void (*Test_TestClass_destructor)(Test_TestClass*);
void (*Test_TestClass_TestVirtual)(Test_TestClass*, int);
} Test_TestClass_vtable;
typedef struct {
Test_TestStruct *(*Test_TestStruct_construct)();
void (*Test_TestStruct_dispose)(Test_TestStruct*);
int *(*Test_TestStruct_get_Data)(Test_TestStruct*);
int *(*Test_TestStruct_set_Data)(Test_TestStruct*, int);
Test_TestClass *(*Test_TestClass_construct)();
Test_TestClass *(*Test_TestClass_construct_derived(const Test_TestClass_vtable*);
void (*Test_TestClass_dispose)(Test_TestClass*);
void (*Test_TestClass_TestMethod)(const Test_TestClass*, Test_TestStruct*);
void (*Test_TestClass_TestVirtual)(Test_TestClass*, int);
} api_interface;
api_host.h
#include "api.h"
void init_api_interface(api_interface&);
api_host.cpp
#include "header.h"
#include "api.h"
// wrapper class
class _derived_TestClass : public Test::TestClass {
public:
_derived_TestClass(const Test_TestClass_vtable &vtable) : _vtable(vtable) {
}
~_derived_TestClass() {
if (_vtable.Test_TestClass_destructor) {
_vtable.Test_TestClass_destructor(reinterpret_cast<Test_TestClass*>(this));
}
}
void TestVirtual(int v) override {
if (_vtable.Test_TestClass_TestVirtual) {
_vtable.Test_TestClass_TestVirtual(reinterpret_cast<Test_TestClass*>(this), v);
} else {
TestClass::TestVirtual(v);
}
}
private:
const Test_TestClass_vtable &_vtable;
};
// wrapper functions
Test_TestStruct *_api_Test_TestStruct_construct() {
return reinterpret_cast<Test_TestStruct*>(new TestStruct());
}
void _api_Test_TestStruct_dispose(Test_TestStruct *p) {
auto *phost = reinterpret_cast<TestStruct*>(p);
delete phost;
}
int *_api_Test_TestStruct_get_Data(Test_TestStruct *p) {
return &reinterpret_cast<TestStruct*>(p)->Data;
}
...
...
// sets the values of all function pointers
void init_api_interface(api_interface &iface) {
iface.Test_TestStruct_construct = _api_Test_TestStruct_construct;
iface.Test_TestStruct_dispose = _api_Test_TestStruct_dispose;
iface.Test_TestStruct_get_Data = _api_Test_TestStruct_get_Data;
...
...
}
When I compile the host program, I compile all these files into an executable, and call init_api_interface() to initialize the function pointers. When other people compile plugins, they only include api.h, and compile the files into a dynamic library with a certain exposed function, say init_plugin(const api_interface*). When the user loads a plugin, the host program only needs to pass a pointer to the struct to init_plugin in the dynamic library, and the plugin can set off to use all these functions.
The benefits of using such a scheme is that:
Plugins compiled using different toolchains than the host program should work fine.
The list of API functions can be extended without breaking existing plugins, as long as new function pointers are added after existing ones.
This approach allows full access to routines in the host program, while it's also easy to hide certain aspects.
It allows plugins to inherit from classes in the host program, which is kinda important for my case.
Plugin developers don't need the source of the host program.
It's convenient since the API interface doesn't need to be manually maintained.
Of course, this is just a gist of the approach and many more details need to be considered in practice.
So my questions are:
Is this kind of plugin interface good practice? Are there existing examples of this approach? Are there better solutions to this problem? Is there any critical drawbacks of this approach that I don't see?
Can SWIG accomplish this task? If not, can SWIG be modified to do so?
If SWIG must be modified, which is easier, modifying SWIG or starting from scratch using clang?
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
I'm relatively new to C++ and I feel like I'm in over my head. I'm trying to create a graph structure that can take any kind of data by using templates. Here is c_graph.h
#pragma once
#include <vector>
#include <unordered_map>
#include <unordered_set>
template <class T> class c_graph {
private:
std::unordered_map<T,std::unordered_set<T>> adj_matrix;
public:
'' GRAPH OPERATIONS OMITTED ''
};
template <class M> struct node {
public:
M val;
node() {
}
node(M v) {
val = v;
}
};
I would like to support using data directly (hence the template T on the graph), or wrapping the data in a node struct, which is defined at the bottom. My reason for the node struct is sometimes you want different nodes in the graph to have the same data, which wouldn't work with the unordered_map on the outside of the adjacency matrix without a data wrapper.
However I've run into an issue with the unordered_set class. It doesn't have a hash function for node. I read about this problem online and the solution seems to be something like
namespace std {
template <class M> class hash<node<M>> {
public:
size_t operator()(const node<M> &n) const
{
return reinterpret_cast<size_t>(&n);
}
};
};
I have another .cpp file that is trying to use c_graph<node<char>>
However for the life of me I can't get my code to compile. I've tried placing the hash snippet inside c_graph.h, where I get a bunch of linker errors
error LNK2019: unresolved external symbol "public: void __thiscall c_graph<struct node<char> >::add_node(struct node<char>)"...
and I've tried placing it inside c_graph.cpp, where I get
error C2338: The C++ Standard doesn't provide a hash for this type.
Turns out you can't really separate template function declarations from template function implementations. Linker error when using a template class?
Moving the contents of c_graph.cpp into c_graph.h got rid of the linker errors