I am actually working on a project, which has one file like this.
#include "Preference.h"
#include <string>
#include <list>
#include <exception>
namespace MedicalStudentMatcher
{
class PreferenceException: public std::exception
{
public:
PreferenceException(std::string message) : m_message(message) {}
virtual ~PreferenceException() { }
virtual const char* what() const throw()
{
return m_message.c_str();
}
private:
std::string m_message;
};
class PreferenceReader
{
public:
PreferenceReader(std::string filename);
virtual ~PreferenceReader();
std::list<Preference<std::string, std::string>> ReadPreferences();
private:
std::string m_filename;
std::string trim(std::string str);
};
}
Now the questions are
1. How is the constructor working ? (Please bear in mind that I am a newbie to STL in C++ , and any kind of advanced methods in C++)
2. Explain the syntax of what() function.(Why there are two const then a char * and then a throw)
3. What does the below line mean
std::list<Preference<std::string, std::string>> ReadPreferences();
4. I want to traverse through this list. How do I go about it.?
list<Preference<string, string>> hospitalPrefs = hospitalReader.ReadPreferences();
list<Preference<string, string>> studentPrefs = studentReader.ReadPreferences();
list<Match<string, string>> matches;
5. How do template class work in the following case and how is preference class using it. What is P m_preferrer declare ? How are "initialisation list" working in this case?
template <class P, class O>
class Preference
{
private:
P m_preferrer;
O m_preferred;
int m_value;
public:
Preference(const P& preferrer, const O& preferred, int value) : m_preferrer(preferrer), m_preferred(preferred), m_value(value) {}
virtual ~Preference() {}
P getPreferrer() const { return m_preferrer; }
O getPreferred() const { return m_preferred; }
int getValue() const { return m_value; }
};
template <class P, class O>
bool less_than(const Preference<P, O>& p1, const Preference<P, O>& p2)
{
return p1.getValue() < p2.getValue();
}
}
Even after thorough googling i couldn't find answer to these question.
Please help. if you need any more info on other files, kindly comment.
The PreferenceException constructor uses an "initialization list" to set m_message. Now that you know that term, you can search for it to learn more.
virtual const char* what() const throw() declares "A virtual (runtime polymorphic) function which returns a pointer to (an array of) characters, where that pointer cannot be used to modify those characters." The trailing "const throw()" mean "This function cannot modify its implicit this argument, i.e. it cannot modify the instance of the class on which it was called, and it cannot throw any exceptions."
That's a member function declaration. The function should be defined elsewhere. The function returns a (doubly-linked) list of Preferences.
Try this:
list<Preference<string, string>> hospitalPrefs = hospitalReader.ReadPreferences();
for (Preference<string, string>& pref : hospitalPrefs)
{
// do something with pref
}
Or if you're stuck on C++98 instead of C++11:
list<Preference<string, string>> hospitalPrefs = hospitalReader.ReadPreferences();
for (list<Preference<string, string>>::iterator it = hospitalPrefs.begin(); it != hospitalPrefs.end(); ++it)
{
// do something with pref
}
Related
I originally had a problem creating a map of classes, with some help
I realized I actually need a map<string, unique_ptr<myclass>>.
To be more precise:
I have a bunch of specialized classes with a common ancestor.
specialized classes are actually specialized from the same template.
I have a std::map<std::string, unique_ptr<ancestor>> taking ownership
of my instances (I hope).
I need ownership because the function creating the instances is in a
completely different section of code than the place using them.
If useful: I create the map at initialization time and then I only
reference it at runtime; for all practical purposes after initializing
it (a complex affair, involving reading config files) it could become
const.
A minimal example of what I need to achieve is:
#include <iostream>
#include <string>
#include <memory>
#include <map>
class generic {
std::string _name;
public:
generic(std::string name) : _name(name) {}
virtual ~generic() = default;
virtual std::string name() { return _name; }
virtual std::string value() { return "no value in generic"; }
};
template <class T> class special : public generic {
T _value;
public:
special(std::string name, T value) : generic(name), _value(value) {}
virtual ~special() = default;
std::string value() override { return std::to_string(_value); }
};
template <typename T> void add_item(std::map <std::string, std::unique_ptr<generic>> &m, const std::string &n, const T &v) {
m[n] = std::make_unique<special<T>>(typeid(v).name(), v);
}
int
main() {
std::map <std::string, std::unique_ptr<generic>> instances;
add_item<int>(instances, "int", 1);
add_item<bool>(instances, "bool", true);
add_item<float>(instances, "float", 3.1415);
for (auto i : instances) {
std::cout << i.first << " -- " << i.second.get()->name() << " -- " << i.second.get()->value() << std::endl;
}
return 0;
}
Unfortunately I seem to be missing something because compilation bombs with "error: use of deleted function".
Can someone be so kind to help me sort this out?
In this loop you try to copy unique_ptrs, but the unique_ptr copy constructor is deleted.
for (auto i : instances) {
You need to take them by reference instead:
for (auto& i : instances) {
I have an algorithm (not preseted here) which takes as input different parameters (int, float, vectors).
My idea of design was to have an container which holds all these differents parameters.
To achive this, I have a base class Parameter and a derivated template class TypeParameter.
These parameters will be holded in a container.
The design is presented below:
#pragma once
#include <utility>
#include <memory>
#include <string>
#include <vector>
namespace parameter
{
/*
Interface for parameter
*/
class Parameter
{
public:
Parameter() {}
Parameter(std::string param_name) : name(param_name) {}
Parameter(const Parameter&& other) noexcept : name(std::move(other.name)) {}
virtual ~Parameter() {}
inline const std::string get_name() { return name; }
private:
std::string name;
};
/*
*/
template<class T>
class TypeParameter
: public Parameter
{
public:
TypeParameter(std::string param_name, T new_value) : Parameter(param_name), value(new_value) {}
TypeParameter(const TypeParameter&& other) noexcept : Parameter(std::move(other)), value(std::move(other.T)) {}
inline const T get_value() { return value; }
private:
T value;
};
/*
Container for parameters
*/
class ParameterSet
{
public:
ParameterSet() {}
void add(std::unique_ptr<Parameter> param) { data.push_back(std::move(param)); }
private:
std::vector <std::unique_ptr<Parameter>> data;
};
} //namespace parameter
The main is:
#include <iostream>
#include <string>
#include "Parameter.h"
using parameter::TypeParameter;
using parameter::Parameter;
using parameter::ParameterSet;
void foo(std::unique_ptr<Parameter> p)
{
std::cout << p->get_value(); // ERROR
}
int main(int argc, char *argv[])
{
TypeParameter<int> *iparam = new TypeParameter<int>("ee", 3);
std::unique_ptr<Parameter> p = std::make_unique <TypeParameter<int>>("foo", 3);
foo(std::move(p));
ParameterSet param_set;
param_set.add(std::unique_ptr<Parameter>(iparam));
param_set.add(std::move(p));
getchar();
}
My problem is I cannot get the value without a cast.
Hence, my question is how do I cast the unique_ptr from a Parameter class to derived TypeParameter.
Is there another way to design the container?
Thanks a lot!
You don't have to reinvent the wheel. There are a couple of classes you can use from the standard library:
std::variant.
As suggested by the comments, variant is a type-safe union of a pre-defined set of data types, which you put in the templates argument of variant.
For example, a std::variant<int,float,double> can hold any value of type int, float, or double, but nothing else.
To use the stored value, you can either use the visitor pattern with the std::visit() function. Other functions allow you to know which of the preset types is stored in the variable (index()) and to extract the value from it (using get()). If you try to extract the value of the wrong type, the get() function throws an exception
std::any
is another utility that can hold different data types. As opposed to variant, you don't have to know the types at compile-time. Basically, it stores a void* to the data with a typeinfo to remember its original type. You can then use any_cast to cast the variable back to its original type. Just like variant, an exception is thrown when trying to cast to the wrong type.
These two classes are available in C++ 17. If these features are not available to you, they were also included in boost (respectively boost:variant and boost:any)
You can store the set of values in a standard library container, e.g. in a std::vector<std::variant<int,float,double>> or a std::vector<std::any>>.
Alternative to std::variant/std::any is the old way polymorphism:
class Parameter
{
public:
Parameter(const std::string& param_name) : name(param_name) {}
virtual ~Parameter() = default;
const std::string& get_name() const { return name; }
virtual void printValue() const = 0;
// Other virtual methods
private:
std::string name;
};
template<class T>
class TypeParameter : public Parameter
{
public:
TypeParameter(const std::string& name, const T& t) : Parameter(name), value(t) {}
// Non virtual method when we don't access it by base class.
const T& get_value() const { return value; }
void printValue() const { std::cout << value; }
private:
T value;
};
And then your
void foo(const Parameter& p)
{
std::cout << p.get_value(); // ERROR
}
becomes
void foo(const Parameter& p)
{
p.print();
}
If you don't want to add many virtual methods to Parameter, then Visitor pattern can help, but then you have to know each derived types.
I'm trying to make a list of template classes of variable types. So the idea is to loop of a list of objects that all have a common function, e.g. getValue, but a different type. The type could be any type, raw types or objects.
I need this because i want to have a class that has a list of attributes of different types that i want to be able to construct at runtime.
So my class would look something like:
class MyClass {
std::list<Attribute<?>*> attributes;
};
And my attribute template:
template<typename T>
class Attribute {
public:
Test(const T &t) : _t(t) {}
T getValue() const { return _t; }
void setValue(const T &t) { _t = t; }
private:
T _t;
};
int main() {
MyClass myClass;
myClass.attributes.push_back(new Attribute<int>(42));
myClass.attributes.push_back(new Attribute<double>(42.0));
}
As you can see the list of MyClass i put ? because that is my problem. I dont know how to make a list that will take different types of my Attribute template, i.e. int, double etc.
std::list<Attribute<?> *> attributes;
In Java, generics can be used for that. Is it possible in C++ to do this with somekind of construction? I tried using variadic templates but that doesnt seem to help solving my problem.
I need this but not in Java, in C++:
public class GenericAttribute<T> {
private T value;
public GenericAttribute (T value) {
setValue(value);
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
public static void main(String[] args) {
class Custom {
public Custom() {}
#Override public String toString() {
return "My custom object";
}
}
List<GenericAttribute<?>> attributes = new ArrayList<GenericAttribute<?>>();
attributes.add(new GenericAttribute<Integer>(1));
attributes.add(new GenericAttribute<Double>(3.1415926535));
attributes.add(new GenericAttribute<Custom>(new Custom()));
for (GenericAttribute<?> attr : attributes) {
System.out.println(attr.getValue());
}
}
Output:
1
3.1415926535
My custom object
Thanks for the help!
Version 3: Very Advanced (do not try that at home :D)
class Attribute {
private:
struct Head {
virtual ~Head() {}
virtual void *copy() = 0;
const type_info& type;
Head(const type_info& type): type(type) {}
void *data() { return this + 1; }
};
template <class T> struct THead: public Head {
THead(): Head(typeid(T)) {}
virtual ~THead() override { ((T*)data())->~T(); }
virtual void *copy() override {
return new(new(malloc(sizeof(Head) + sizeof(T)))
THead() + 1) T(*(const T*)data()); }
};
void *data;
Head *head() const { return (Head*)data - 1; }
void *copy() const { return data ? head()->copy() : nullptr; }
public:
Attribute(): data(nullptr) {}
Attribute(const Attribute& src): data(src.copy()) {}
Attribute(Attribute&& src): data(src.data) { src.data = nullptr; }
template <class T> Attribute(const T& src): data(
new(new(malloc(sizeof(Head) + sizeof(T))) THead<T>() + 1) T(src)) {}
~Attribute() {
if(!data) return;
Head* head = this->head();
head->~Head(); free(head); }
bool empty() const {
return data == nullptr; }
const type_info& type() const {
assert(data);
return ((Head*)data - 1)->type; }
template <class T>
T& value() {
if (!data || type() != typeid(T))
throw bad_cast();
return *(T*)data; }
template <class T>
const T& value() const {
if (!data || type() != typeid(T))
throw bad_cast();
return *(T*)data; }
template <class T>
void setValue(const T& it) {
if(!data)
data = new(new(malloc(sizeof(Head) + sizeof(T)))
THead<T>() + 1) T(it);
else {
if (type() != typeid(T)) throw bad_cast();
*(T*)data = it; }}
public:
static void test_me() {
vector<Attribute> list;
list.push_back(Attribute(1));
list.push_back(3.14);
list.push_back(string("hello world"));
list[1].value<double>() = 3.141592;
list.push_back(Attribute());
list[3].setValue(1.23f);
for (auto& a : list) {
cout << "type = " << a.type().name()
<< " value = ";
if(a.type() == typeid(int)) cout << a.value<int>();
else if (a.type() == typeid(double)) cout << a.value<double>();
else if (a.type() == typeid(string)) cout << a.value<string>();
else if (a.type() == typeid(float)) cout << a.value<float>();
cout << endl;
}
}
};
Output:
type = i value = 1
type = d value = 3.14159
type = Ss value = hello world
type = f value = 1.23
Explanation:
Attribute contains data pointer, which is initializaed by this strange placement new: new(new(malloc(sizeof(Head) + sizeof(T))) THead<T>() + 1) T(src) which first allocates enough room for the Head (should be 2*sizeof(void*) which should be just fine for any allignment of any architecture) and the type itself, constructs THead<T>() (initializes pointer to virtual method table and type info) and moves the pointer after the head = at the place we want data. The object is then constructed by another placement new using copy-constructor (or move-constructor) T(src). struct Head has two virtual functions - destructor and copy() which is implemented in THead<T> and used in Attribute(const Attribute&) copy-constructor. Finally ~Attribute() destructor calls ~Head() virtual destructor and releases the memory (if data != nullptr).
Version 1: Simple Attribute List
#include <vector>
#include <typeinfo>
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
class Attributes {
public:
typedef pair<const type_info&,void*> value_type;
typedef vector<value_type> vect;
typedef vect::const_iterator const_iterator;
template <class T>
void add(const T& value) {
data.push_back(pair<const type_info&,void*>(
typeid(T), new(malloc(sizeof(T))) T(value))); }
const_iterator begin() const {
return data.begin(); }
const_iterator end() const {
return data.end(); }
private:
vect data;
} attrs;
int main() {
attrs.add(1);
attrs.add(3.14);
for (auto a : attrs) {
cout << a.first.name() << " = ";
if(a.first == typeid(int))
cout << *(int*)a.second;
else if(a.first == typeid(double))
cout << *(double*)a.second;
cout << endl;
}
}
Output:
i = 1
d = 3.14
Version 2 (named attributes):
#include <string>
#include <unordered_map>
#include <typeinfo>
#include <iostream>
#include <cstdlib>
#include <new>
using namespace std;
class Attributes {
public:
typedef pair<const type_info&,void*> value_type;
typedef unordered_map<string,value_type> map;
typedef map::const_iterator const_iterator;
template <class T>
bool add(const string& name, const T& value) {
auto it = data.insert(make_pair(
name, value_type(typeid(T), nullptr)));
if (!it.second) return false;
it.first->second.second = new(malloc(sizeof(T))) T(value);
return true; }
template <class T>
const T& get(const string& name) const {
auto it = data.at(name);
if (it.first != typeid(T)) throw bad_cast();
return *(T*)it.second; }
const_iterator begin() const {
return data.begin(); }
const_iterator end() const {
return data.end(); }
void erase(const_iterator it) {
free(it->second.second);
data.erase(it); }
bool remove(const string& name) {
auto it = data.find(name);
if (it == data.end()) return false;
free(it->second.second);
data.erase(it);
return true; }
private:
map data;
} attrs;
int main() {
attrs.add("one", 1);
attrs.add("pi", 3.14);
cout << "pi = " << attrs.get<double>("pi") << endl;
attrs.remove("pi");
for (auto a : attrs) {
cout << a.first << " = ";
if(a.second.first == typeid(int))
cout << *(int*)a.second.second;
else if(a.second.first == typeid(double))
cout << *(double*)a.second.second;
cout << endl;
}
}
Take a look at variant - this is a class that can be one of a number of different types, but you don't mind which until you need to operate on the values, in which case you can use the visitor pattern to visit all the types.
It is effectively a C++ type-aware version of the C 'union' construct but as it 'knows' which type was set, it can offer type safety.
The biggest issue with variants is that if you expose your implementation and allow any client to put pretty much any type into your variant (attributes.push_back(new Attribute<Widget>(myWidget));), you're going to be unable to do anything with it. E.g. if you want to do 'sum' on all the values put into your attributes, you'd need them to be convertible to a numeric representation and a Widget might not be.
The bigger question is what are you trying to do with them once you've captured these items as Attributes? Enumerating through them calling getValue() is going to give you different results depending on what types you put in. A visitor object would work, but it's still not clear what value this would bring.
It could be that you need something different, such as an interface, e.g. IAttribute that abstracts the underlying type as long as it conforms to the interface which has a getValueAsDouble() method or getValueAsString() method, which you could do to any type that got passes in - no need for variant or visitor in this case.
As Attribute<int> is different type than Attribute<double>, you can't use list or vector without creating a common base type.
Alternatively, you may store different type into a std::tuple.
Following may help:
template <typename ... Ts>
class MyClass {
public:
MyClass(const Ts&... args) : attributes(args...) {}
private:
std::tuple<Attribute<Ts>...> attributes;
};
int main()
{
MyClass<int, double> myClass(42, 42.0);
return 0;
}
As you already pointed out, in java it is much easier to do so because all classes extends java.lang.Object. In C(++), there is a similar way, but only for pointers - you can use void* for this. Your list will look something like this then:
std::list<Attribute<void*> *> attributes;
Sure, a void* doesn't save the type. If you need, add this field to your Attribute-class:
public:
std::type_info type;
Then, if you create an instance of Attributre, do this (probably from the constructor):
type = typeinfo(type_to_store);
Of corse, if you do so from the constructor, you'll need to run typeinfo in the code that calls the constructor.
Then, you can get the name of the class back from that field and the instance back from your void*:
std::string name = attribute->type_info.name();
void * instance = attribute->getValue();
What operations do you want to perform on this collection? Do you want to, say, call getValue on all of the Attribute<int> instances and ignore the others? In that case, a base class is fine—you just don’t make the getValue member function virtual (because its type depends on the subclass) and use RTTI to recover the type information at runtime:
struct AnyAttribute {
// Needs at least one virtual function to support dynamic_cast.
virtual ~AnyAttribute() {}
};
template<typename T>
struct Attribute : AnyAttribute { … };
int main() {
std::vector<AnyAttribute*> attributes;
attributes.push_back(new Attribute<int>(13));
attributes.push_back(new Attribute<int>(42));
attributes.push_back(new Attribute<double>(2.5));
for (const auto attribute : attributes) {
if (const auto int_attribute = dynamic_cast<Attribute<int>>(attribute)) {
std::cout << int_attribute->getValue() << '\n';
}
}
}
An obvious, but naive solution will be:
inherit Attribute<T> from base AttributeBase
store AttributeBase (smart-)pointers in container (downcast)
when reading container element, somehow figure out its type (RTTI)
cast back to derived Attribute<T> (upcast)
You can beautify this ugly solution by adding another level of indirection: make a generic container, that stores generic containers for each attribute, so casting will happen under the hood.
You can use integrated to language RTTI features, such as type_info but as far as I know, it's reliability is questionable. Better solution will be to wrap up some kind of static unique id to each Attribute<T> class and put an accessor to AttributeBase to retrieve it. You can add a typedef to relevant Attribute<T> to your unique id class to make casting easier.
So far so good, but in modern C++, we know, that when you need RTTI, it, probably, means that there is something wrong with your overall code design.
I don't know what exact task you have, but my "gut feelings" say me that you will probably can eliminate need of RTTI by using multiple dispatch (double dispatch), such as Visitor pattern in your code (they always say that when see RTTI).
Also, check some other tricks for inspiration:
More C++ Idioms/Coercion by Member Template
I have a map which represents a configuration. It's a map of std::string and boost::any.
This map is initialized at the start and I'd like the user to be able to override these options on the command line.
What I'd love to do is build the program options from this map using the options_description::add_option() method. However, it takes a template argument po::value<> whereas all I have is boost::any.
So far, I just have the shell of the code. m_Config represents my configuration class, and getTuples() returns a std::map<std::string, Tuple>. TuplePair is a typedef of std::pair<std::string, Tuple> and the Tuple contains the boost::any I am interested in.
po::options_description desc;
std::for_each(m_Config.getTuples().begin(),
m_Config.getTuples().end(),
[&desc](const TuplePair& _pair)
{
// what goes here? :)
// desc.add_options() ( _pair.first, po::value<???>, "");
});
Is there a way to build it this way, or do I need to resort to doing it myself?
Thanks in advance!
boost::any is not applicable to your problem. It performs the most basic form of type erasure: storage and (type-safe) retrieval, and that's it. As you've seen, no other operations can be performed. As jhasse points out, you could just test every type you want to support, but this is a maintenance nightmare.
Better would be to expand upon the idea boost::any uses. Unfortunately this requires a bit of boiler-plate code. If you'd like to try it, there's a new Boost library being discussed right now on the mailing list (titled "[boost] RFC: type erasure") that is essentially a generalized type erasure utility: you define the operations you'd like your erased type to support, and it generates the proper utility type. (It can simulate boost::any, for example, by requiring the erased type be copy-constructible and type-safe, and can simulate boost::function<> by additionally requiring the type be callable.)
Aside from that, though, your best option is probably to write such a type yourself. I'll do it for you:
#include <boost/program_options.hpp>
#include <typeinfo>
#include <stdexcept>
namespace po = boost::program_options;
class any_option
{
public:
any_option() :
mContent(0) // no content
{}
template <typename T>
any_option(const T& value) :
mContent(new holder<T>(value))
{
// above is where the erasure happens,
// holder<T> inherits from our non-template
// base class, which will make virtual calls
// to the actual implementation; see below
}
any_option(const any_option& other) :
mContent(other.empty() ? 0 : other.mContent->clone())
{
// note we need an explicit clone method to copy,
// since with an erased type it's impossible
}
any_option& operator=(any_option other)
{
// copy-and-swap idiom is short and sweet
swap(*this, other);
return *this;
}
~any_option()
{
// delete our content when we're done
delete mContent;
}
bool empty() const
{
return !mContent;
}
friend void swap(any_option& first, any_option& second)
{
std::swap(first.mContent, second.mContent);
}
// now we define the interface we'd like to support through erasure:
// getting the data out if we know the type will be useful,
// just like boost::any. (defined as friend free-function)
template <typename T>
friend T* any_option_cast(any_option*);
// and the ability to query the type
const std::type_info& type() const
{
return mContent->type(); // call actual function
}
// we also want to be able to call options_description::add_option(),
// so we add a function that will do so (through a virtual call)
void add_option(po::options_description desc, const char* name)
{
mContent->add_option(desc, name); // call actual function
}
private:
// done with the interface, now we define the non-template base class,
// which has virtual functions where we need type-erased functionality
class placeholder
{
public:
virtual ~placeholder()
{
// allow deletion through base with virtual destructor
}
// the interface needed to support any_option operations:
// need to be able to clone the stored value
virtual placeholder* clone() const = 0;
// need to be able to test the stored type, for safe casts
virtual const std::type_info& type() const = 0;
// and need to be able to perform add_option with type info
virtual void add_option(po::options_description desc,
const char* name) = 0;
};
// and the template derived class, which will support the interface
template <typename T>
class holder : public placeholder
{
public:
holder(const T& value) :
mValue(value)
{}
// implement the required interface:
placeholder* clone() const
{
return new holder<T>(mValue);
}
const std::type_info& type() const
{
return typeid(mValue);
}
void add_option(po::options_description desc, const char* name)
{
desc.add_options()(name, po::value<T>(), "");
}
// finally, we have a direct value accessor
T& value()
{
return mValue;
}
private:
T mValue;
// noncopyable, use cloning interface
holder(const holder&);
holder& operator=(const holder&);
};
// finally, we store a pointer to the base class
placeholder* mContent;
};
class bad_any_option_cast :
public std::bad_cast
{
public:
const char* what() const throw()
{
return "bad_any_option_cast: failed conversion";
}
};
template <typename T>
T* any_option_cast(any_option* anyOption)
{
typedef any_option::holder<T> holder;
return anyOption.type() == typeid(T) ?
&static_cast<holder*>(anyOption.mContent)->value() : 0;
}
template <typename T>
const T* any_option_cast(const any_option* anyOption)
{
// none of the operations in non-const any_option_cast
// are mutating, so this is safe and simple (constness
// is restored to the return value automatically)
return any_option_cast<T>(const_cast<any_option*>(anyOption));
}
template <typename T>
T& any_option_cast(any_option& anyOption)
{
T* result = any_option_cast(&anyOption);
if (!result)
throw bad_any_option_cast();
return *result;
}
template <typename T>
const T& any_option_cast(const any_option& anyOption)
{
return any_option_cast<T>(const_cast<any_option&>(anyOption));
}
// NOTE: My casting operator has slightly different use than
// that of boost::any. Namely, it automatically returns a reference
// to the stored value, so you don't need to (and cannot) specify it.
// If you liked the old way, feel free to peek into their source.
#include <boost/foreach.hpp>
#include <map>
int main()
{
// (it's a good exercise to step through this with
// a debugger to see how it all comes together)
typedef std::map<std::string, any_option> map_type;
typedef map_type::value_type pair_type;
map_type m;
m.insert(std::make_pair("int", any_option(5)));
m.insert(std::make_pair("double", any_option(3.14)));
po::options_description desc;
BOOST_FOREACH(pair_type& pair, m)
{
pair.second.add_option(desc, pair.first.c_str());
}
// etc.
}
Let me know if something is unclear. :)
template<class T>
bool any_is(const boost::any& a)
{
try
{
boost::any_cast<const T&>(a);
return true;
}
catch(boost::bad_any_cast&)
{
return false;
}
}
// ...
po::options_description desc;
std::for_each(m_Config.getTuples().begin(),
m_Config.getTuples().end(),
[&desc](const TuplePair& _pair)
{
if(any_is<int>(_pair.first))
{
desc.add_options() { _pair.first, po::value<int>, ""};
}
else if(any_is<std::string>(_pair.first))
{
desc.add_options() { _pair.first, po::value<std::string>, ""};
}
else
{
// ...
}
});
// ...
If you have more than a handful of types consider using typelists.
I've got an interesting problem that's cropped up in a sort of pass based compiler of mine. Each pass knows nothing of other passes, and a common object is passed down the chain as it goes, following the chain of command pattern.
The object that is being passed along is a reference to a file.
Now, during one of the stages, one might wish to associate a large chunk of data, such as that file's SHA512 hash, which requires a reasonable amount of time to compute. However, since that chunk of data is only used in that specific case, I don't want all file references to need to reserve space for that SHA512. However, I also don't want other passes to have to recalculate the SHA512 hash over and over again. For example, someone might only accept files which match a given list of SHA512s, but they don't want that value printed when the file reference gets to the end of the chain, or perhaps they want both, or... .etc.
What I need is some sort of container which contain only one of a given type. If the container does not contain that type, it needs to create an instance of that type and store it somehow. It's basically a dictionary with the type being the thing used to look things up.
Here's what I've gotten so far, the relevant bit being the FileData::Get<t> method:
class FileData;
// Cache entry interface
struct FileDataCacheEntry
{
virtual void Initalize(FileData&)
{
}
virtual ~FileDataCacheEntry()
{
}
};
// Cache itself
class FileData
{
struct Entry
{
std::size_t identifier;
FileDataCacheEntry * data;
Entry(FileDataCacheEntry *dataToStore, std::size_t id)
: data(dataToStore), identifier(id)
{
}
std::size_t GetIdentifier() const
{
return identifier;
}
void DeleteData()
{
delete data;
}
};
WindowsApi::ReferenceCounter refCount;
std::wstring fileName_;
std::vector<Entry> cache;
public:
FileData(const std::wstring& fileName) : fileName_(fileName)
{
}
~FileData()
{
if (refCount.IsLastObject())
for_each(cache.begin(), cache.end(), std::mem_fun_ref(&Entry::DeleteData));
}
const std::wstring& GetFileName() const
{
return fileName_;
}
//RELEVANT METHOD HERE
template<typename T>
T& Get()
{
std::vector<Entry>::iterator foundItem =
std::find_if(cache.begin(), cache.end(), boost::bind(
std::equal_to<std::size_t>(), boost::bind(&Entry::GetIdentifier, _1), T::TypeId));
if (foundItem == cache.end())
{
std::auto_ptr<T> newCacheEntry(new T);
Entry toInsert(newCacheEntry.get(), T::TypeId);
cache.push_back(toInsert);
newCacheEntry.release();
T& result = *static_cast<T*>(cache.back().data);
result.Initalize(*this);
return result;
}
else
{
return *static_cast<T*>(foundItem->data);
}
}
};
// Example item you'd put in cache
class FileBasicData : public FileDataCacheEntry
{
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
unsigned __int64 size;
public:
enum
{
TypeId = 42
}
virtual void Initialize(FileData& input)
{
// Get file attributes and friends...
}
DWORD GetAttributes() const;
bool IsArchive() const;
bool IsCompressed() const;
bool IsDevice() const;
// More methods here
};
int main()
{
// Example use
FileData fd;
FileBasicData& data = fd.Get<FileBasicData>();
// etc
}
For some reason though, this design feels wrong to me, namely because it's doing a whole bunch of things with untyped pointers. Am I severely off base here? Are there preexisting libraries (boost or otherwise) which would make this clearer/easier to understand?
As ergosys said already, std::map is the obvious solution to your problem. But I can see you concerns with RTTI (and the associated bloat). As a matter of fact, an "any" value container does not need RTTI to work. It is sufficient to provide a mapping between a type and an unique identifier. Here is a simple class that provides this mapping:
#include <stdexcept>
#include <boost/shared_ptr.hpp>
class typeinfo
{
private:
typeinfo(const typeinfo&);
void operator = (const typeinfo&);
protected:
typeinfo(){}
public:
bool operator != (const typeinfo &o) const { return this != &o; }
bool operator == (const typeinfo &o) const { return this == &o; }
template<class T>
static const typeinfo & get()
{
static struct _ti : public typeinfo {} _inst;
return _inst;
}
};
typeinfo::get<T>() returns a reference to a simple, stateless singleton which allows comparisions.
This singleton is created only for types T where typeinfo::get< T >() is issued anywhere in the program.
Now we are using this to implement a top type we call value. value is a holder for a value_box which actually contains the data:
class value_box
{
public:
// returns the typeinfo of the most derived object
virtual const typeinfo& type() const =0;
virtual ~value_box(){}
};
template<class T>
class value_box_impl : public value_box
{
private:
friend class value;
T m_val;
value_box_impl(const T &t) : m_val(t) {}
virtual const typeinfo& type() const
{
return typeinfo::get< T >();
}
};
// specialization for void.
template<>
class value_box_impl<void> : public value_box
{
private:
friend class value_box;
virtual const typeinfo& type() const
{
return typeinfo::get< void >();
}
// This is an optimization to avoid heap pressure for the
// allocation of stateless value_box_impl<void> instances:
void* operator new(size_t)
{
static value_box_impl<void> inst;
return &inst;
}
void operator delete(void* d)
{
}
};
Here's the bad_value_cast exception:
class bad_value_cast : public std::runtime_error
{
public:
bad_value_cast(const char *w="") : std::runtime_error(w) {}
};
And here's value:
class value
{
private:
boost::shared_ptr<value_box> m_value_box;
public:
// a default value contains 'void'
value() : m_value_box( new value_box_impl<void>() ) {}
// embedd an object of type T.
template<class T>
value(const T &t) : m_value_box( new value_box_impl<T>(t) ) {}
// get the typeinfo of the embedded object
const typeinfo & type() const { return m_value_box->type(); }
// convenience type to simplify overloading on return values
template<class T> struct arg{};
template<class T>
T convert(arg<T>) const
{
if (type() != typeinfo::get<T>())
throw bad_value_cast();
// this is safe now
value_box_impl<T> *impl=
static_cast<value_box_impl<T>*>(m_value_box.get());
return impl->m_val;
}
void convert(arg<void>) const
{
if (type() != typeinfo::get<void>())
throw bad_value_cast();
}
};
The convenient casting syntax:
template<class T>
T value_cast(const value &v)
{
return v.convert(value::arg<T>());
}
And that's it. Here is how it looks like:
#include <string>
#include <map>
#include <iostream>
int main()
{
std::map<std::string,value> v;
v["zero"]=0;
v["pi"]=3.14159;
v["password"]=std::string("swordfish");
std::cout << value_cast<int>(v["zero"]) << std::endl;
std::cout << value_cast<double>(v["pi"]) << std::endl;
std::cout << value_cast<std::string>(v["password"]) << std::endl;
}
The nice thing about having you own implementation of any is, that you can very easily tailor it to the features you actually need, which is quite tedious with boost::any. For example, there are few requirements on the types that value can store: they need to be copy-constructible and have a public destructor. What if all types you use have an operator<<(ostream&,T) and you want a way to print your dictionaries? Just add a to_stream method to box and overload operator<< for value and you can write:
std::cout << v["zero"] << std::endl;
std::cout << v["pi"] << std::endl;
std::cout << v["password"] << std::endl;
Here's a pastebin with the above, should compile out of the box with g++/boost: http://pastebin.com/v0nJwVLW
EDIT: Added an optimization to avoid the allocation of box_impl< void > from the heap:
http://pastebin.com/pqA5JXhA
You can create a hash or map of string to boost::any. The string key can be extracted from any::type().