I have several "resources" in my code base. All of them are classes and share the same interface except one class, the ShaderProgram is different in just one way, it needs two strings for files names of the vertex and fragment files.
I have a template class called ResourceManager that handles all these resource except the shader one because it needs two files and the others need one, can I solve this with a template specialization? It needs to be that ResourceManager sees GetOrLoadFromFile( string, string ) and not (string) versions, while the others have the opposite, they see (string) and not (string, string). Also AttemptLoad needs the treatment too. How can I make a solution for this please include code, I have never done template specializations before.
template < class ResType > class ResourceManager
{
public:
ResourceManager(void);
~ResourceManager(void);
SmartPointer<ResType> GetOrLoadFromFile( const std::string & fileName );
//weak_ptr<ResType> GetResourceFromID( ResourceID & resID );
void DestroyResources();
void ReleaseResources();
void ReloadResources();
protected:
private:
SmartPointer<ResType> AttemptLoad( const std::string & fileName );
std::unordered_map<string, SmartPointer<ResType> > mResMap;
};
// Relevant methods ( SNIPPED )
template < class ResType> SmartPointer<ResType> ResourceManager<ResType>::GetOrLoadFromFile( const std::string & fileName )
{
if ( !mResMap.empty() )
{
auto index = mResMap.begin();
auto end = mResMap.end();
while ( index != end )
{
if ( index->first == fileName )
{
return index->second;
}
++index;
}
}
return AttemptLoad(fileName);
}
template < class ResType > SmartPointer<ResType> ResourceManager<ResType>::AttemptLoad( const std::string & fileName )
{
SmartPointer<ResType> pRes( new ResType() );
if ( pRes->LoadFromFile( fileName ) )
{
mResMap.insert( std::make_pair( fileName, pRes ) );
return pRes;
}
else
{
LogFailure("Failed to load resource file " + fileName)
return SmartPointer<ResType>(nullptr);
}
}
If both classes are under your control I would suggest a different solution. Why don't you change the AttempLoad method into something like
SmartPointer<ResType> AttemptLoad( const LoadConfiguration &p_loadConfiguration );
Where
class LoadConfiguration
{
public:
std::string FirstFileName;
};
and
class ExtendedLoadConfiguration : public LoadConfiguration
{
public:
std::string SecondFileName;
};
you could then always work with LoadConfiguration and each AttemptLoad would be able to take what he needs. Adding new arguments will be easy, it's less code with the same signature and you wouldn't have to work with template specialization.
The idea behind templates is that you known your types before the execution times, i.e., at compilation time. If this is true, than what you are trying to do is an overloading using templates. So, bellow I just put a generic code, that you can adapt to your code, that do overloading at compilation time.
Note that, to avoid writing code twice, every common methods are put in base class and let to the derived class only the ones that diverges.
#include <memory>
#include <string>
#include <iostream>
using namespace std;
class Base
{
// put common codes here
};
template <typename ResType>
class ResourceManager : public Base
{
public:
unique_ptr<ResType> GetorLoad(const string &f) { cout << f << endl; return 0;}
};
// Specilizing class ResourceManager for string type
template <>
class ResourceManager<string> : public Base
{
public:
unique_ptr<string> GetorLoad(const string &f1, const string &f2) {cout << f1 << f2 << endl; return 0;}
};
int main()
{
ResourceManager<int> i;
ResourceManager<string> s;
i.GetorLoad("int");
s.GetorLoad("string", "string");
}
PS. To compile and test this example, you need to use '--std=c++11' flag from gcc or clang++ compilers
Just implement both 'GetOrLoadFromFile' functions:
#include <string>
struct R1
{
void load (const std::string &name) {}
};
struct R2
{
void load (const std::string &name0, const std::string name1) {}
};
template<typename R>
struct M
{
R *get_or_load (const std::string &name)
{
R *p = new R();
p->load (name);
return p;
}
R *get_or_load (const std::string &name0,
const std::string &name1)
{
R *p = new R();
p->load (name0, name1);
return p;
}
};
M<R1> m1;
M<R2> m2;
int
main ()
{
R1 *p0 = m1.get_or_load ("foo");
// R1 *p1 = m2.get_or_load ("foo"); // error
R2 *q0 = m2.get_or_load ("foo", "bar");
// R2 *q1 = m1.get_or_load ("foo", "bar"); // error
}
The "wrong" member function will not be instantiated, unless actually there's a call to it, in which case the compiler will exit with diagnostics.
Related
I'm trying to refactor some code. Basically is a state machine based with enum.
There are a lot of switch statements and functions that got called with different names and ambiguations.
Since they force me to keep the enum, I would like to refactor it using template. Basically I would like to use template to implement polymorphism. Since the states are limited there should be a way but I cannot find the best one.
#include <iostream>
enum class AnimalType
{
Dog,
Cat
};
template<AnimalType T>
void Foo()
{
std::cout << "Unknown animal\n";
}
template<>
void Foo<AnimalType::Dog>()
{
std::cout << "I'm a dog\n";
}
template<>
void Foo<AnimalType::Cat>()
{
std::cout << "I'm a cat\n";
}
int main()
{
AnimalType CurrentAnimal = AnimalType::Dog;
// Foo<CurrentAnimal>(); Won't compile
return 0;
}
You need a compile time evaluatable constant, this will work
int main()
{
constexpr auto CurrentAnimal = AnimalType::Dog;
Foo<CurrentAnimal>();
return 0;
}
or directly use
Foo<AnimalType::Dog>();
Note : you can't use your construct to make decissions at runtime.
Templates only lead to compile time polymorphism
As mentioned by #P Kramer's answer:
Note : you can't use your construct to make decissions at runtime. Templates only lead to compile time polymorphism.
You can't do that, but you can use the Compile-Time Dispatch and runtime parameter by passing the desired value as parameter while they are separated by Function Template Specialization. For example turn your enumerations value into actual types:
struct animal_t
{
std::string const name;
explicit animal_t(std::string const& name_)
: name(name_)
{
}
auto operator()() const
{
return name;
}
};
struct dog_t final : animal_t
{
using animal_t::animal_t;
};
struct cat_t final : animal_t
{
using animal_t::animal_t;
};
They you are able to specialize the function template:
/*!
*
* Other Programmer(s) interface
*
*/
template<typename Animal>
auto function(Animal const&)
{
assert(false);
}
/*!
*
* Implementation
*
*/
template<>
auto function(cat_t const& animal)
{
return animal();
}
template<>
auto function(dog_t const& animal)
{
return animal();
}
Now user (other programmer) of your library could easily interact with it for example by a GUI library:
QObject::connect(button1, &QPushButton::clicked, &application, [] {
cat_t cat("Some Cat");
auto const message = QString::fromStdString(function(cat));
QMessageBox::information(nullptr, " ", message);
});
QObject::connect(button2, &QPushButton::clicked, &application, [] {
dog_t dog("Some Dog");
auto const message = QString::fromStdString(function(dog));
QMessageBox::information(nullptr, " ", message);
});
Result: just for copy/past: runtime_dispatch_v1
I have a set of multiple C++ classes that have the same interface (not derived from each other though). I'm trying to wrap these to make them available in .NET.
I currently have a method that defines the wrapper class using C/C++ #defines and then I can subsequently instantiate classes with a simple line of code
However I can't debug this. Ideally I would like to be able to use a generic or a template. However I can't use a C++ type inside a generic which would be the ultimate way to solve this problem.
Has anyone any idea of how I can do this without using the dreaded macros?
EDIT:
OK Here is an example of the templated class I have written:
template< typename CPPResamplerClass >
ref class TResampler
{
CPPResamplerClass* pResampler;
public:
TResampler( int inputSampleRate, int outputSampleRate, int bufferLen ) :
pResampler( new CPPResamplerClass( inputSampleRate, outputSampleRate, bufferLen ) )
{
}
~TResampler()
{
this->!ResamplerName();
}
!TResampler()
{
if (pResampler)
{
delete pResampler;
pResampler = nullptr;
}
}
property int HistorySize
{
int get()
{
return pResampler->HistorySize();
}
}
array< float >^ ResampleAudio(array< float >^ in)
{
pResampler->Get
array< float >^ out = gcnew array< float >(in->Length);
cli::pin_ptr< float > pIn = &in[0];
cli::pin_ptr< float > pOut = &out[0];
unsigned int inLen = in->Length;
unsigned int outLen = out->Length;
if (pResampler->ResampleAudio(pOut, outLen, pIn, inLen))
{
System::Array::Resize(out, outLen);
return out;
}
return nullptr;
}
};
typedef TResampler< ::Vec::SpeexResample > SpeexResample;
I then want to access this from C# however SpeexResample does not exist. This could well be because I am using a typedef ...
Templates don't exist until they're instantiated. While you could instantiate one explicitly:
template ref class TResampler<SomeNativeClass>;
It wouldn't be exactly user-friendly to use from C#. The exported type will literally have angle brackets in its name. Good luck using that. In C# it's only doable through reflection.
The next best thing is to use derived types. Here's a minimal example:
#include "stdafx.h"
#include <iostream>
namespace CppCli {
class NativeClassA
{
int foo;
public:
NativeClassA(int foo) : foo(foo) { std::cout << "Built native class A" << std::endl; }
int getFoo() const { return foo; }
};
class NativeClassB
{
int foo;
public:
NativeClassB(int foo) : foo(foo) { std::cout << "Built native class B" << std::endl; }
int getFoo() const { return foo; }
};
template<typename NativeClass>
public ref class ManagedWrapper
{
NativeClass* ptr;
public:
ManagedWrapper(int foo)
: ptr(new NativeClass(foo))
{}
~ManagedWrapper()
{
this->!ManagedWrapper();
}
!ManagedWrapper()
{
if (ptr)
{
delete ptr;
ptr = nullptr;
}
}
property int Foo { int get() { return ptr->getFoo(); } }
};
public ref class ManagedWrapperA : ManagedWrapper<NativeClassA>
{
public:
ManagedWrapperA(int foo) : ManagedWrapper(foo) {}
};
public ref class ManagedWrapperB : ManagedWrapper<NativeClassB>
{
public:
ManagedWrapperB(int foo) : ManagedWrapper(foo) {}
};
};
Sure enough, ManagedWrapperA and ManagedWrapperB are visible from C#. Maybe you could macro these definitions and still get a decent debugging experience.
I want to write a class that can monitor a bunch of different values for easy debugging. Imagine setting "watches" in a visual debugger. I'm picturing something like this:
struct Foo {
int x = 0;
std::string s = "bar";
};
int main() {
Foo f;
ValueMonitor::watch("number", &f.x);
ValueMonitor::watch("string", &f.s);
for (int i = 0; i < 10; ++i) {
++f.x;
if (i > 5) {
f.s = "new string";
}
// print the current value of the variable with the given key
// these should change as the loop goes on
ValueMonitor::print("number");
ValueMonitor::print("string");
// or
ValueMonitor::printAll();
// obviously this would be unnecessary in this example since I
// have easy access to f, but imagine monitoring different
// values from all over a much larger code base
}
}
Then these could be easily monitored somewhere in the application's GUI or whatever.
However, I don't know how to handle the different types that would be stored in this class. Ideally, I should be able to store anything that has a string representation. I have a few ideas but none of them really seem right:
Store pointers to a superclass that defines a toString function or operator<<, like Java's Object. But this would require me to make wrappers for any primitives I want to monitor.
Something like boost::any or boost::spirit::hold_any. I think any needs to be type casted before I can print it... I guess I could try/catch casting to a bunch of different types, but that would be slow. hold_any requires defined stream operators, which would be perfect... but I can't get it to work with pointers.
Anyone have any ideas?
I found a solution somewhere else. I was pretty blown away, so might as well post it here for future reference. It looks something like this:
class Stringable
{
public:
virtual ~Stringable() {};
virtual std::string str() const = 0;
using Ptr = std::shared_ptr<Stringable>;
};
template <typename T>
class StringableRef : public Stringable
{
private:
T* _ptr;
public:
StringableRef(T& ref)
: _ptr(&ref) {}
virtual ~StringableRef() {}
virtual std::string str() const
{
std::ostringstream ss;
ss << *_ptr;
return ss.str();
}
};
class ValueMonitor
{
private:
static std::map<std::string, Stringable::Ptr> _values;
public:
ValueMonitor() {}
~ValueMonitor() {}
template <typename T>
static void watch(const std::string& label, T& ref)
{
_values[label] = std::make_shared<StringableRef<T>>(ref);
}
static void printAll()
{
for (const auto& valueItr : _values)
{
const String& name = valueItr.first;
const std::shared_ptr<Stringable>& value = valueItr.second;
std::cout << name << ": " << value->str() << std::endl;
}
}
static void clear()
{
_values.clear();
}
};
std::map<std::string, Stringable::Ptr> ValueMonitor::_values;
.
int main()
{
int i = 5;
std::string s = "test"
ValueMonitor::watch("number", i);
ValueMonitor::watch("string", s);
ValueMonitor::printAll();
i = 10;
s = "new string";
ValueMonitor::printAll();
return 0;
}
is there any way to declare a variety number of member variables from different user-data type generically using template operator?
consider this code:
class a {
int member;
void ProcessMemberVariable ();
};
class b {
char member;
void ProcessMemberVariable ();
};
... // arbitrary number of such classes
class test {
template <typename T>
void declare (T a ) {
// each time this member function is called a new member variable of the
// user data type T shall be declared in the instance of the class test??
}
};
int ()
{
test Test;
Test.template declare<a>(a A);
Test.template declare<b>(b B);
...
}
Imagine You want to implement an interface which is apple to set any kind of user defined data type. Since I know the identifier of user-defined data type only when I declare an instance of class "test" and call its member function...
I appreciate each suggestion..
What you are describing sounds like dynamically adding members to an object, and this isn't possible in C++. There are various ways to get a similar effect in certain situations, but you would need to describe a situation where you thought this would be useful.
As stated there is no way to dynamically add member variables at runtime.
However, if you know the list of types that you may want to add at runtime you could achieve this behaviour using boost::variant. Below is a trivial example (
#include <iostream>
#include <string>
#include <map>
#include <boost/variant.hpp>
using namespace std;
class Test
{
public:
typedef boost::variant< long, double, string > VariantType;
template< typename T >
void Declare( std::string name, T val )
{
VariantType newVal = val;
varMap.insert( std::make_pair( std::move( name ), std::move( val ) ) );
}
VariantType Get( const std::string& name )
{
return varMap[ name ];
}
template< typename T >
T GetValue( const std::string& name )
{
return boost::get<T>( varMap[name] );
}
private:
std::map< string, VariantType > varMap;
};
int main()
{
Test t{};
t.Declare( "Var1", 10l );
t.Declare( "pi", 3.14159);
t.Declare( "AString", "SomeName" );
cout << "t.get( Var1 ) " << t.GetValue<long>( "Var1" ) << "\n";
cout << "t.get( pi ) " << t.GetValue<double>( "pi" ) << "\n";
cout << "t.get( AString ) " << t.GetValue<string>( "AString" ) << "\n";
return 0;
}
See: http://www.boost.org/doc/libs/1_49_0/doc/html/variant.html for details on how to use boost::variant.
I have this function in some library:
class myConsole
{
void addCommand( std::string command, void* fn );
...
}
and in my class I have this function:
void myApp::TestFn( const std::vector<std::string> & args )
{
// do something
}
in the same class I call this:
void myApp::initApp( )
{
myConsole::getSingleton( ).addCommand( "FirstTest", &myApp::TestFn );
}
but this gives me this error:
error c2664 cannot convert parameter 2 from 'void(__thiscall
myApp::*)(const std::vector<_Ty>&)' to 'void *'
how can I solve this?
thanks in advance!
You can't solve this. You can't reliably cast a function pointer to void * and back.
(I suggest you redesign the program and stay clear of void*; there's no real need for it in C++.)
The problem here is that you are trying to pass a class method as it were a void * pointer. This cannot be done.
The right way of doing this is by using templates for the void addCommand (std::string, void *) method. Something like
class myConsole {
template <typename T>
void addCommand( std::string command, T f);
};
struct Callback {
myApp &app;
Callback (myApp &a) : app(a) {
}
void operator() (const std::vector<std::string> &args) {
app.TestFn(args);
}
};
void myApp::initApp( )
{
myConsole::getSingleton( ).addCommand( "FirstTest", Callback(*this) );
}
This gives you the callback principle in C++, but I think you need something more flexible than this solution, since you actually want to choose automatically the command that will be executed by the callback (in this case TestFn).
You should avoid void*, especially when trying to use function pointers. I'm going to assume that you are looking only at member-function pointers in the myApp class, and that you are only interested in member-function pointers which take const std::vector<std::string> &args as an argument. This typedef will create the appropriate type and call it MemFunType
typedef void (myApp :: * MemFunType) (const std::vector<std::string> &);
Here is a complete example (on ideone), where there are two different member-functions you may be interested in, TestFn and TestFnBackwards. This example probably isn't very useful, but it gives some examples of member-function pointers.
#include<iostream>
#include<vector>
using namespace std;
struct myApp;
struct myConsole
{
typedef void (myApp :: * MemFunType) (const std::vector<std::string> &);
void addCommand( std::string command, MemFunType fn );
};
struct myApp {
void TestFn( const std::vector<std::string> & args ) {
cout << " TestFn" << endl;
for(std :: vector<std::string> :: const_iterator i = args.begin(); i!=args.end(); i++) {
cout << *i << endl;
}
}
void TestFnBackwards( const std::vector<std::string> & args ) {
cout << " TestFnBackwards" << endl;
for(std :: vector<std::string> :: const_reverse_iterator i = args.rbegin(); i!=args.rend(); i++) {
cout << *i << endl;
}
}
static myApp & getSingleton();
} ma;
myApp& myApp :: getSingleton() {
return ma;
}
void myConsole :: addCommand( std::string , MemFunType fn ) {
vector<string> words;
words.push_back("hello");
words.push_back("world");
myApp &ma = myApp :: getSingleton();
(ma.*fn)(words); // execute the member on the singleton object, using the words as the argument.
}
int main() {
myConsole m;
m.addCommand( "FirstTest", &myApp::TestFn );
m.addCommand( "FirstTest", &myApp::TestFnBackwards );
}