Im trying to figure out how to store my template, ill write a example:
class cDebugInfo
{
private:
DWORD * address;
string name;
template Type;
public:
Type GetFormattedValue()
{
return *(Type*)address;
}
cDebugInfo(){}
template <class T>
cDebugInfo(DWORD Address, string Name){
address = Address;
name = Name;
Type = T;
}
};
My goal, is to be able to add a item to my array:
std::vector<cDebugInfo>DebugItems;
template <class T>
void AddItem(std::string name, DWORD Address)
{
DebugItems.push_back(cDebugInfo(Address, name));
}
cDebugInfo* GetItemByNameP(std::string name)
{
for (int i = 0; i < DebugItems.size(); i++)
{
if (DebugItems[i].name == name)
{
return &DebugItems[i];
}
}
}
So i add the items to my array like this:
AddItem<int>(0x1337, "Test");
AddItem<string>(0x1337, "Test2");
And Therefore being able to call:
GetItemByName("Test")->GetFormattedValue();
And that should return the value in INT read form the given address since the template passed when i add the item, is a int. And ofcourse, the following should return the value stored in the address pointed by my pointer as a string:
GetItemByName("Test2")->GetFormattedValue();
I need it to "remember" what template was passed on to the class.
NOTE: Everything else works fine when i use GetItemByName with a template, but the thing is i dont know what template it is when i get them, only when i add them.
Thank you.
What you are asking for is not possible because every expression in C++ must have a known type at compile time. Consider this:
auto value = GetItemByName("BestItem")->GetFormattedValue();
GetItemByName(...) gives me a cDebugInfo*, but what does GetFormattedValue() give me? This must be the same type for every cDebugInfo* so that the above expression can be valid, so the type cannot withheld until runtime. So the general solution is impossible.
However, you can add specific solutions based on what it is you want to do. Let's say we just want to be able to print the formatted value. We can do that:
class cDebugInfo {
std::function<void()> printer; // type-erased functor
...
public:
template <class T>
cDebugInfo(DWORD Address, string Name){
address = Address;
name = Name;
printer = [this]{
std::cout << "Value as " << typeid(T).name() << ": "
<< *reinterpret_cast<T*>(address) << '\n';
};
}
};
This approach is called "type erasure". In this case, the lambda "stores" the type T, but the class itself just needs to know that it's a nullary function that returns void. We can expose that via:
void printValue() { printer(); }
So that:
GetItemByValue("BestItem")->printValue();
will print the value correctly based on the type it was constructed with.
Related
I'm trying to create something like this:
// The code doesn't work, it should just be a pseudo to help understand what i'm trying to create
template <typename Variable>
class Address
{
unsigned int A_Address;
Variable A_Type;
void Set(A_Type value)
{
*((A_Type*)A_Address) = value;
}
A_Type Get()
{
return *((A_Type*)A_Address);
}
};
Address address_1 = new Address<float/*type*/>(0x00000000/*address in memory*/);
address_1.Set(30.0f);
float value_1 = address_1.Get();
Address address_2 = new Address<int/*type*/>(0x00000000/*address in memory*/);
address_2.Set(10);
int value_2 = address_2.Get();
So i want to be able to define objects like Address obj_1, obj_2; and then Initialize them later with a type and an address. Then the Get() method should return it's current value in memory and the Set() method should set that value in memory. I couldn't figure out how to not do Address<float> obj_1; and instead using Address obj_1; and initializing it later. Hope you understood what i'm trying to do and could let me know if it's possible and if so maybe help me out or point me in the right direction.
Thanks in advance!
I'm not really dealing with your address mangling but what you want can be done that way :
struct Address
{
Address(unsigned int addr)
: A_Address(addr)
{}
unsigned int A_Address;
template <typename T>
void Set(T value)
{
*((T*)A_Address) = value;
}
template <typename T>
T Get()
{
return *((T*)A_Address);
}
};
And you can use it that way
Address address(0x00000000); //won't work because of virtual addressing
address.Set<float>(10.0F);
std::cout << address.Get<float>();
address.Set<double>(99.0);
std::cout << address.Get<double>();
Be careful when you handle addresses that way, very error-prone. Have a look over there:
Pass a hex address to a Pointer Variable
I would like to have a program that parses and manages command-line parameters for me. As you can see in the main-function, by using simple commands like Option<int>("number", { "-n", "--number" }) you can specify the type the option's value should have (like int in this case), an unique identifier for each option (like "number"), and multiple strings this option can be introduced with. Also, many options should be wrapped in a class called OptionSet, which simplifies access to its options.
But in my actual code, I am having several problems right now:
I want to store multiple instances of one class with different template parameters within one std::vector. For example, in my code, Option<int> should be stored in the same vector like Option<std::string> and Option<double>.
Maybe it's even possible to store the template parameters separately in another vector?
By using using, std::enable_if_t and std::is_same I created a type called OptionHasValue. If the template parameter Invert is false and T is void, OptionHasValue has an invalid type, otherwise it has the type specified by the template parameter U.
The class OptionValue uses OptionHasValue and a bit of SFINAE magic to decide if it should have the needed methods for supporting the storage of values or not. That is, the first version of OptionValue has OptionHasValue<T> as its second template parameter, so it becomes invalid (and removed by the compiler) if T is void. The other version of OptionValue has the opposite behavior, because its second template parameter is OptionHasValue<T, true> and the true inverts the behavior of OptionHasValue.
The class Option itself inherits from OptionValue, so if you create an option like Option<void>, it does not have support for values (that is, it lacks functions like setValue, setValueFromString and getValue as it should). On the other hand, if you create an option like Option<int>, the resulting class instance has all of these features.
The problem now is, that (for example) OptionSet::process() accesses both Option::hasValue and Option::setValueFromString, but the latter is only declared if Option::hasValue is true (and the corresponding template parameter for the option is not void). But because Option::setValueFromString is not wrapped in some kind of template here, the compiler also complains.
In my main-function I use the function optionSet.getOptionValue(std::string). This function should return the value of an option (after it has been set after process() has been called). The difficult thing now is that the return type depends on the return value of findOptionByIdentifier, a function which loops through all available options and returns the option with the wanted identifier.
For example, if identifier would be "number" (as in the example for an Option at the beginning of this question), the return type of findOptionByIdentifier would be Option<int>, because the only option having the identifier "number" is the one which has int as its first template parameter, which would finally result in getOptionValue having the return type int.
You can see the expected behavior in comments in some of the last lines of the main-function.
So, what do I have to change in the following code to fix all these things (and to make it compile)? I am using g++ 5.2.0 (mingw-w64), so I may use any feature of C++11 and C++14.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <stdexcept>
#include <type_traits>
#include <boost/lexical_cast.hpp>
#include <boost/any.hpp>
template<typename T, bool Invert = false, typename U = void>
using OptionHasValue = std::enable_if_t<(!std::is_same<T, void>::value) ^ Invert, U>; //only make this template substitution successful, if (when 'Invert' is false) T is not if type 'void'
template<typename T, typename Enable = void>
class OptionValue;
template<typename T>
class OptionValue<T, OptionHasValue<T>> //using SFINAE ("substitution failure is not an error") here
{
protected:
T value;
public:
void setValue(T newValue)
{
value = newValue;
}
void setValueFromString(std::string newValueStr)
{
setValue(boost::lexical_cast<T>(newValueStr));
}
T getValue()
{
return value;
}
bool hasValue()
{
return true; //if this class variant is taken by the compiler, the 'Option' that will inherit from it will have a value
}
};
template<typename T>
class OptionValue<T, OptionHasValue<T, true>> //the opposite condition (the 'true' inverts it)
{
//option value is disabled, but to check if a value is available in the derived class, add a function for that (or should I not?)
public:
bool hasValue()
{
return false;
}
};
template<typename T>
class Option : public OptionValue<T>
{
private:
std::string identifier;
std::vector<std::string> variants;
public:
Option(std::string newIdentifier, std::vector<std::string> newVariants)
{
identifier = newIdentifier;
variants = newVariants;
}
bool hasVariant(std::string v)
{
return (std::find(variants.begin(), variants.end(), v) != variants.end());
}
std::string getIdentifier()
{
return identifier;
}
};
class OptionSet
{
private:
std::vector<boost::any> options; //boost::any can't be the right way to do this, or is it?
std::vector<std::string> argvVec;
template<typename T>
Option<T>& findOptionByIdentifier(std::string identifier)
{
for(auto& o : options)
if(o.getIdentifier() == identifier) //of course this doesn't compile, because 'o' will always be of type 'boost::any', but what should I do instead?
return o;
throw std::runtime_error("error: unable to find option by identifier \"" + identifier + "\"\n");
}
template<typename T>
Option<T>& findOptionByVariant(std::string variant)
{
for(auto& o : options)
if(o.hasVariant(variant)) //probably almost the same compile error like in 'findOptionByIdentifier'
return o;
throw std::runtime_error("error: unable to find option by variant \"" + variant + "\"\n");
}
public:
template<typename t>
void add(Option<T> opt)
{
options.push_back(opt); //is this the right way to add instances of classes with different template parameters to a vector?
}
void setArgvVec(std::vector<std::string> newArgvVec)
{
argvVec = newArgvVec;
}
void process()
{
for(size_t i=0; i<argvVec.size(); i++)
{
Option<T>& opt = findOptionByVariant(argvVec[i]); //of course this doesn't compile either, but what should I do instead?
if(opt.hasValue())
{
if(i == argvVec.size()-1)
throw std::runtime_error("error: no value given for option \"" + argvVec[i] + "\"\n");
opt.setValueFromString(argvVec[i]); //boost::bad_lexical_cast should be caught here, but that's not important right now
i++;
}
}
}
template<typename T>
T getOptionValue(std::string identifier)
{
Option<T>& opt = findOptionByIdentifier(identifier); //a bit like the call to 'findOptionByVariant' in 'process()'. also, this variable does not have to be a reference
if(!opt.hasValue())
throw std::runtime_error("error: option with identifier \"" + identifier + "\" has no value\n");
return opt.getValue();
}
};
int main()
{
OptionSet optionSet;
//it's not guaranteed that OptionSet::add will always receive a rvalue, I just do it here for shorter code/simplicity
optionSet.add(Option<void>("help", { "-?", "--help" })); //if it's a void-option, the 'Option' does not have a value, if the template parameter is anything else, it has one (like below)
optionSet.add(Option<std::string>("message", { "-m", "--message" }));
optionSet.add(Option<int>("number", { "-n", "--number" }));
optionSet.add(Option<double>("pi", { "-p", "--pi" }));
optionSet.setArgvVec({ "--help", "-m", "hello", "--number", "100", "--pi", "3.14" });
optionSet.process();
std::string message = optionSet.getOptionValue("message");
int number = optionSet.getOptionValue("number");
double pi = optionSet.getOptionValue("pi");
std::cout << "Message: " << message << "\n"; //should output 'hello'
std::cout << "Number: " << number << "\n"; //should output '100'
std::cout << "Pi: " << pi << "\n"; //should output something like '3.140000'
return 0;
}
I am not sure I fully understood the question, but I will try to answer it.
I want to store multiple instances of one class with different
template parameters
There is no such thing. A template with different template paramter is a different class. However, you seem to be solving it successfully through boost::any. You could also use another type-erasure technique - for example, have a non-template parent to all your options, or switch to non-type-erasure boost::variant, as it seems like you only have a limited number of possible option types.
By using using, std::enable_if_t and std::is_same I created a type
called OptionHasValue...
First of all, I would not use SFINAE in this example. Simple partial specialization will suffice. As for opt.setValueFromString(argvVec[i]); just create a NOOP function in void option class.
As for the last question, just use a templated function which receives a reference to the return type, instead of returning it.
I have a very simple C++ lookup table for dispatching commands:
template <class T> Action* CreateAction(Command *c)
{
return new T(c);
}
typedef Action* CreateActionFunc(Command *c);
typedef struct ActionTable {
string name;
CreateActionFunc *func;
} ActionTableEntry;
vector<ActionTableEntry> GlobalActionTable = {
{ "quit" , &CreateAction<DoQuit> },
};
This works fine, but I would rather have my CreateAction function construct the new object on the stack and return it by value. But when I write this:
template <class T> T CreateAction(Command *c)
{
return T(c);
}
typedef Action CreateActionFunc(Command *c);
Then the program will no longer compile. First I get an error that an abstract class cannot be instantiated (on the typedef line) and also an error that the initialization list for the table doesn't match the type of the vector.
There is a very similar question here but every answer uses new in the factory methods, which is explicitly what I'm trying to avoid. How can this be done?
You can't use polymorphism with objects by value.
Need to be pointers or reference.
I'm guessing here you have an Action interface (so an abstract class), so you can't create an object of this dynamic type. All you can do is send a pointer of type Action with a dynamic type of a Derived Class (so what you are already doing i assume).
You could create a value object of a derived type on the stack and return a reference on the Base class and still use polymorphism, but then you'll need to address the lifetime of the Derived object problem.
The Action sub class has more information than the Action class itself - pointers to a table of it's member function, data members etc. There's not enough memory to hold this information if you return by value. Something called slicing would occur.
This answer explains it better.
How about doing something like this instead:
class Action {
void do_something(Command& params) = 0;
};
class SayHello {
void do_something(Command& params) { std::cout << "Hi!" << std::endl; }
}
class SayBye {
void do_something(Command& params) { std::cout << "Goodbye." << std::endl; }
}
.....
SayHello hello;
SayBye bye;
Quit quit;
std::map<string, Action&> action_table = {
{"hello", hello},
{"bye", bye},
{"quit", quit},
};
....
Action& getAction(Command* command) {
...;
return action_from_map;
}
This creates the action once, and returns them by reference.
What about something simple like this?
std::map<string, std::function<void(CommandArgs const&)>> action_table =
{
{"hello", [](CommandArgs const& args) { /* do something */ }},
};
Im trying to create a system capable of allocating any type, and grouping same types together in arrays.
I want to be able to retrieve each array later using so I can iterate over each type.
Something like this:
ObjectDatabase
{
template<typename T>
T* Allocate();
template<typename T>
Array<T>& GetObjects();
}
My Array type is actually a pool so allocation/deletion is fast.
I thought about mapping each Array in a std::map using an int representing the type id for each T, but then each type T would need to inherit from a base class, so it can be stored in the map, and thus leading to casting when I iterate over the array.
I think this pattern has been done before but I'm not sure how.
Can someone help?
Update:
So I'm trying to basically create a structure like this:
struct ObjectDatabase
{
Array<Entities> mEntities;
Array<Transforms> mTransforms;
Array<Physics> mPhysics;
Array<Graphics> mGraphics;
}
But I wanted to somehow create the set of arrays at compile time.. using templates?
Then provide template functions to get access to each array, and to allocate from each array
You probably want to use templates to do type elision. Here's an example that may be similar to what you're looking for. The ObjectDatabase class uses templates and polymorphism internally to do type elision so the classes used don't have any constraints on them (other than the normal constraints for being placed in a standard library container).
#include <iostream>
#include <typeinfo>
#include <deque>
#include <map>
#include <cassert>
using namespace std;
struct ObjectDatabase {
ObjectDatabase() { }
template<typename T>
T &allocate() {
deque<T> &a = getObjects<T>();
a.push_back(T());
return a.back();
}
template<typename T>
deque<T> &getObjects() {
CollectionBase *&el = m_obdb[typeid(T).name()];
if ( not el )
el = new Collection<T>();
Collection<T> *elc = dynamic_cast<Collection<T>*>(el);
assert(elc);
deque<T> &a = elc->elements;
return a;
}
~ObjectDatabase() {
for ( ObDB::iterator i=m_obdb.begin(); i!=m_obdb.end(); ++i)
delete i->second;
}
private:
ObjectDatabase(ObjectDatabase const &);
ObjectDatabase &operator=(ObjectDatabase const &);
struct CollectionBase {
virtual ~CollectionBase() { }
};
template<typename T>
struct Collection : CollectionBase {
deque<T> elements;
};
typedef map<string, CollectionBase *> ObDB;
ObDB m_obdb;
};
struct Foo {
Foo() : name("Generic Foo") { }
char const *name;
};
struct Bar {
string name;
};
int main() {
ObjectDatabase obdb;
obdb.allocate<Foo>().name = "My First Foo";
obdb.allocate<Bar>().name = "My First Bar";
{
Foo &f = obdb.allocate<Foo>();
f.name = "My Second Foo";
Bar &b = obdb.allocate<Bar>();
b.name = "My Second Bar";
}
obdb.allocate<Foo>();
obdb.allocate<Bar>();
{
cout << "Printing Foo Names\n";
deque<Foo> &foos = obdb.getObjects<Foo>();
for ( deque<Foo>::iterator i = foos.begin(); i!=foos.end(); ++i )
cout << " -> " << i->name << "\n";
}
{
cout << "Printing Bar Names\n";
deque<Bar> &bars = obdb.getObjects<Bar>();
for ( deque<Bar>::iterator i = bars.begin(); i!=bars.end(); ++i )
cout << " -> " << i->name << "\n";
}
}
When I run this program, I get this output:
Printing Foo Names
-> My First Foo
-> My Second Foo
-> Generic Foo
Printing Bar Names
-> My First Bar
-> My Second Bar
->
This shows that the individual objects are stored in containers specific to their own type. You'll notice that Foo and Bar are nothing special, just regular aggregates. (Foo would even be a POD if it weren't for its default constructor.)
======== EDIT ========
If you don't want to use RTTI, you need to get rid of the typeid and dynamic_cast.
Getting rid of the dynamic_cast is fairly simple --- you don't actually need it. You can use static_cast instead; you just can't check that the derived type is correct with the assert() anymore. (But if the type was wrong, it would be a bug anyway.)
The typeid is a bit trickier, since that is used to construct an identifier to differentiate between different concrete types. But you can use some template magic and static objects to replace the string (from type_info::name()) with a simple void const * pointer:
template<typename T>
struct TypeTag {
static char const tag;
};
template<typename T>
char const TypeTag<T>::tag = '\0';
template<typename T>
void const *get_typemarker() {
return &TypeTag<T>::tag;
}
Now we can use get_typemarker<T>() to return a void const * key into the map. We change the type of ObDB's key from string to void const * and replace typeid(T).name() with get_typemarker<T>(). I've tested it and it gives the same output in my test program as the RTTI-enabled version.
I'm trying to write a function for a database class that is basically just a wrapper around a hash_map of objects (say shapes) indexed by ID numbers that will look up an ID and cast it to the appropriate pointer type.
e.g. I'd like to be able to do something like this:
Circle* shapeToLookup = NULL;
int idNum = 12;
database.lookup(idNum, circleToLookup);
if(circleToLookup != NULL)
{
// Do stuff with the circle.
}
and have the database know the type of its argument. Is there a way to do this without either overloading the function (lookup(int, Circle*), lookup(int, Rect*), ad nauseum)? Can you declare a function like lookup(int, Shape*) and have it know which type it's given?
Thanks!
template <T>
Database::lookup(int idNum, T TobjectToLookup)
{
// inside here, T is the type of the object passed in/
}
You can do it with a template.
Edit: new implementation based on the extra information. If mymap is a std::map<int, Shape*>:
template <typename T>
void lookup(int idNum, T* &ptr) {
auto it = mymap.find(idNum);
if (it == mymap.end()) {
ptr = 0;
} else {
ptr = dynamic_cast<T*>(*it); // Shape must have a virtual member function
}
}
Or you might prefer:
template <typename T>
T* lookup(int idNum) {
auto it = mymap.find(idNum);
if (it == mymap.end()) {
return 0;
}
return dynamic_cast<T*>(*it);
}
Then call it like Circle *circle = database.lookup<Circle>(123);
Obviously polymorphic containers are a whole heap of fun in themselves, but I'll assume you have that sorted. There may well be a shared_ptr in there somewhere that I've left out.
Old implementation when I thought the DB might store copies of POD:
template <typename T>
void lookup(int idNum, T* &ptr) {
void *theresult = // something based on idNum
// some check needed here that theresult really is the right type.
// how you do this depends on the database, but suppose that
// the database gives us some integer "type" which indicates the type
if (type != type_constant<T>::value) {
ptr = 0;
} else {
ptr = static_cast<T*>(theresult);
}
}
type_constant is an example of "type traits", you implement it like:
template <typename T>
struct type_constant {};
template <>
struct type_constant<Circle> {
static const int value = 1;
};
template <>
struct type_constant<Rectangle> {
static const int value = 2;
};
// etc...
Others have explained how to pass a type to a function (by using function templates). I'd like to give another point of view:
It might be even better to introduce a new virtual function on Shape and then move the Do stuff with the Circle part into the reimplementation of that virtual function in the Cricle class.
That way, you remove the need to know the type. You just fetch a Shape object from your database and then call a doStuff() function - and it does the right thing depending on the actual type of the Shape. A good use case for a virtual function. :-)
Of course, this might be more or less simple, depending on what Do stuff actually does.