I'm try to create a BidirectionalMap class using (only) STL (no, boost is not an option.) I have 99% percent of it working the way that I want, but what I really can't figure out is how to force the template to require two different types so that operator[] can be properly overridden. Something like...
template < class KeyType, class ValueType >
class BidirectionalMap
{
public:
...
const ValueType& operator[](const KeyType& _k ) { return( m_keyMap[ _k ] ); }
const KeyType& operator[](const ValueType& _v ) { return( m_valMap[ _v ] ); }
private:
std::map< KeyType > m_keyMap;
std::map< ValueType > m_valueMap;
};
main()
{
BidirectionalMap< Foo, Foo > fooMap; // won't work, ambiguous.
BidirectionalMap< Foo, Bar > fooBarMap; // does work.
}
Thoughts?
-R
Just add the following partial specialisation:
template <typename T>
class BidirectionalMap<T, T>;
This will case the compiler to instantiate a template that isn’t defined (since the above is only declared) and bail if the user tries to pass the same type as both template arguments.
Of course the real question is: Why such an arbitrary restriction ?
I would consider perfectly normal to have the same type as key and value, so instead of providing an ambiguous operator overload, perhaps could you simply provide two different methods ?
ValueType const& by_key(KeyType const&) const;
KeyType const& by_value(ValueType const&) const;
and be done with it.
EDIT: Following #Georg Fritzsche's remark :)
Remember that one of the paramount rules of overloading is that all overloads should have the same basic meaning.
Related
First of all, I have a template class that looks like this:
template <typename T>
class Configurable
{
public:
//protected:
T var_value;
std::string var_name;
std::string var_type;
Configurable()
: var_value(0), var_name("unnamed"), var_type("undefined")
{}
Configurable( T v_value, std::string v_name, std::string v_type )
: var_value(v_value), var_name(v_name), var_type(v_type)
{}
std::string get_name() {return var_name;}
};
I also have a container class named Config which has a couple of different Configurable lists for storage of Configurable ints, bools and floats. I want to overload the [] operator of Config so that it returns a Configurable with the given name (regardless of the type) from one of the lists, but this doesn't seem to work:
template <typename T>
Configurable<T>& operator[] ( const std::string v_name_arg );
The compiler returns an error of 'no match for operator[]'. So my question is - how can I make this work? Is it even possible to do it using templates or should I find a different approach with inheritance?
EDIT: Sorry for all the confusion. Here's the container class I'm talking about:
class Config
{
public:
//private:
std::list < Configurable<int> > list_int;
std::list < Configurable<float> > list_float;
std::list < Configurable<double> > list_double;
std::list < Configurable<bool> > list_bool;
//public:
Config(){}
template <typename T>
Configurable<T>& operator[] ( const std::string &v_name_arg );
};
The problem with declaring the templated operator[] without any argument that depends on the template parameter is that the compiler cannot determine the type T from a call in the form config["name"].
One solution, considering code readability, would be changing the operator[] to a method such as:
template <typename T>
Configurable<T>& get ( const std::string v_name_arg );
Then, the call should be written like:
config.get<int>("name")
Also, consider passing the string by reference (const std::string&) to avoid unnecessary copies of a std::string passed to the method/operator.
As described above, it's a syntax error.
WHen you write:
template <typename T>
Configurable<T>& operator[] ( const std::string v_name_arg );
You try to define a free standing operator[] as if it would be a free standing function.
But according to your explanations, operator[] should be a member of your container Config.
So the its definition should look somewhat like:
template <typename T>
class Config {
//...
public:
Configurable<T>& operator[] (const std::string v_name_arg) { /* return a ref to a Configurable */ };
};
With such a definition, the stuff compiles, and you can use it for example with :
int main()
{
Configurable<int> c;
Config<int> cfg;
auto a = cfg["test"];
}
I'm having a custom list class and would like to support operations using the "comparison operator" known from the STL. For example:
std::list<MyClass> d;
struct not_key {
not_key( std::string const& str) : str_(str) {}
bool operator( MyClass& elem ) {
return !elem.findThatThing();
}
std::string str_;
};
not_key comp("value");
d.remove_if( comp );
mylist<MyClass> e(d);
e.filter( comp );
And I'm struggling about the signature of a method which accepts these "general" comparison operators. Since all of them have a different type and I don't want static member functions. How can I add a method to my class which accepts the comparison operators?
Thank you very much! :)
If you mean you want to know the signature of mylist::filter you would probably just make it a template with Pred or similar as the type.
template< typename T >
class mylist
{
public:
template< typename Pred >
void filter( Pred pred )
{
// implement, calling pred(elem) for each element or pred(*iter)
}
};
Note that you can pass a free function into that template function, and in C++11 you'll be able to pass in a lambda.
If you want something that isn't a template (other than on the element type) you can use a boost::function (or std::function)
The standard functions (such as std::sort) use a template argument which is deduced to be the type of your comparison function-like object:
template <class UnaryPredicate>
void filter(UnaryPredicate func) {
// Call it like:
func(something);
}
Now UnaryPredicate will be deduced to be the type of whatever function-like object you pass to it. UnaryPredicate makes more sense than calling it a comparison function since it only takes a single argument. A comparison function would typically take two arguments and compare them.
Alternatively, you could take a std::function<bool(const MyClass&)>:
void filter(std::function<bool(const MyClass&)> func) {
// Call it like:
func(something);
}
The signature should be:
bool operator()(Myclass const & elem) const
I have been trying to understand this code
template <typename T, typename _Prd = equal_to<T> >
struct Vector3
{
protected:
T i,j,k;
_Prd comp;
public:
//default constructor
Vector3(void);
//explicit constructor
Vector3(const T& ijk);
//explicit constructor
Vector3(const T& i,const T& j,const T& k);
//copy constructor
Vector3(const Vector3<T,_Prd>& copy_from);
//getters
T I() const;
T J() const;
T K() const;
//setters
void I(const T& i);
void J(const T& j);
void K(const T& k);
//get magnitude of vector.
T Magnitude() const;
//angle between I,J (clockwise)
T Direction() const;
//angle between K and I,J
T Elevation() const;
//scale vector to 1
Vector3<T,_Prd>& Normalize();
//vector scale up-to value
Vector3<T,_Prd>& Scale(const T& length);
...
};
I can't understand first statement
template <typename T, typename _Prd = equal_to<T> > struct Vector3 {};
It's about the usage of equal_to<T>, I found the reference from here and here. But still there isn't anything like this. Thank you for any help to make me understand this part.
Update:
After seeing the answers and reading some text book, my question turns to 2 aspects.
1. Default Template Arguments
In C++11 we can supply default template arguments to a template.
Example from C++ primer 5th ed. Page 670.
#include <functional>
template <typename T, typename F = less<T> >
int compare (const T &v1, const T &v2, F f = F() )
{
if (f(v1, v2) return -1 ;
if (f(v2, v1) return 1 ;
return 0 ;
}
And then we use this template as:
bool i = compare(0,42) ;
The template will use default less function-object class to instantiate.
However, when we use our own objects:
Sales_data item(cin), item2(cin) ;
bool j = compare (item, item2, compareIsbn) ;
Then F turns to compareIsbn function-object instead.
So that the same happens on my question above, this way will leave an entrance to the user of the template to allow them introducing their own function-object, in this case it is used as comparator.
2. Predicates
Check What is predicate in C++?
std::equal_to is a class template, which provides something like this:
bool operator()(T const & lhs, T const & rhs) const { return lhs == rhs; }
In other words, it's a function-object class that wraps the ordinary == comparator. The point is that equal_to can be specialized, and thus provides a non-intrusive way of adding customizability.
On top of that, your template Vector3 also provides an intrusive way of customizing the comparator by way of the second template argument.
Note that predicates are typically objects, and not just trait classes. So your container will actually contain a predicate subobject. If the predicate class is default-constructible, this is no problem, but if it isn't then you must normally provide a copy of the predicate in the container constructor.
As a homework assignment, you can think about how you can avoid spending any actual memory on the predicate subobject.
The second template argument _Prd is assigned a default type much like a function can have default values for arguments. STL uses this heavily. have a look at std::basic_string as an example
I need someone who explain me this code, line by line. I specially don't understand this line:
operator std::map<T, U>()
Thank you very much.
template <typename T, typename U>
class create_map
{
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};
operator std::map<T, U>()
{
return m_map;
}
This is user-defined conversion function.
That means, you can write this:
//obj is an object of type create_map
create_map<int,std::string> obj(1,"Nawaz");
//obj implicitly converts into std::map type!
std::map<int,std::string> map_inst=obj;
See this topic to know more about user-defined conversion function:
User Defined Conversions in C++
You can see this as well: Implicit conversion sequences (C++ only)
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
This actually overloads the operator(), which internally inserts or updates (key,val) pair into the m_map; just see the function definition as to what it does.
So using this function you can write code like this,
obj(2,"Sarfaraz"); //this inserts the pair into the underlying m_map;
I would also suggest you to explore std::map a bit more, especially the overloaded operator[] in std::map.
Code:
template <typename T, typename U>
class create_map
{
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};
The purpose of this code is to be able to specify a map with specific key/value pairs, by chaining calls to operator(), like
create_map<int, std::string>( 1, "blah" )( 2, "hah" )( 3, "doh" )
Since the class does not have a default constructor, there's no way to use it to create an empty map. That may be by design. Or it may be a design error.
The
operator std::map<T, U>()
{
return m_map;
}
defines a conversion to std::map<T, U>, which is the end result of it all.
It can be invoked implicitly wherever a create_map is specified and a std::map is expected, such as using a create_map expression as argument in a function call.
However, it can be pretty inefficient since it copies the map. The compiler may well optimize away the copying. But it’s ungood to needlessly rely on Quality Of Implementation (although sometimes that is the best that one can do).
So it should instead be
operator std::map<T, U> const& () const
{
return m_map;
}
The const at the end there allows a create_map to be declared as const and used.
With this conversion to reference there is the same problem as with using reference arguments, namely a theoretical possibility of aliasing, where code that retains a reference to const is not prepared to deal with changes of the referred object. But in practice it’s not a problem. For example, as formal argument one just writes std::string const& s (instead of just std::string s) as a matter of course, and very few if any errors result from that – I’ve never experienced any problem.
Cheers & hth.,
There's not much to understand about it. operator std::map<T, U>() overrides the class' conversion operator (which takes no parameters) to provide an object instance of type std::map<T, U>. std::map is a STL standard class for associative key->value storage. In your case it maps from keys of type T to values of type U. T and U have been undefined so far (you wrote template class, but where are the template parameters?)
The conversion operator allows to use the class instance in place of the type the operator provides conversion for, like this.
class foo {
operator char const *() {
return "foo instance as char const *";
}
};
// ...
void bar(foo &f)
{
// here the class instance is used as if it were a char const *
cout << f << endl;
}
The line
operator std::map<T, U>()
defines a function that will be called when your create_map object is used like an std::map somewhere in the code.
An easier example would be:
class A
{
public:
operator int()
{
return 3;
}
};
int main()
{
A a;
cout << a << endl;
}
Now the computer finds out that it doesn't know how to print variable a, but it knows how to convert it to an int and then print it. So "3" gets printed.
I'm building a series of predicates that duplicate lots of code, and so are being changed into a single template function class based on the std::unary_function. The idea is that my class interface requires methods such as Element_t Element() and std::string Name() to be defined, so the predicate template arguments are the object type and a value type to which comparison will be made as follows:
// generic predicate for comparing an attribute of object pointers to a specified test value
template <class U, typename R>
class mem_fun_eq : public std::unary_function <U*, bool> {
private:
typedef R (U::*fn_t)();
fn_t fn;
R val;
public:
explicit mem_fun_eq (fn_t f, R& r) : fn(f), val(r) { }
bool operator() (U * u) const {
return (u->*fn)() == val;
}
};
Thus, if I have:
class Atom {
public:
const Element_t& Element() const { return _element; }
const std::string& Name() const { return _name; }
};
I would like to perform a search on a container of Atoms and check for either the Name or Element equality using my template predicate like so:
typedef std::string (Atom::*fn)() const;
Atom_it it = std::find_if( _atoms.begin(), _atoms.end(), mem_fun_eq <Atom, std::string> ((fn)&Atom::Name, atomname));
but compiling this returns the following error on the std::find_if line:
error: address of overloaded function with no contextual type information
Also, trying to form the same predicate for a check of the Element() as such:
typedef Atom::Element_t& (Atom::*fn)() const;
Atom_it it = std::find_if(_atoms.begin(), _atoms.end(), mem_fun_eq <Atom, Atom::Element_t> ((fn)&Atom::Element, elmt);
creates a different error!
error: no matching function for call to ‘mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(Atom::Element_t& (Atom::*)()const, const Atom::Element_t&)’
note: candidates are: mem_fun_eq<U, R>::mem_fun_eq(R (U::*)(), R&) [with U = Atom, R = Atom::Element_t]
note: mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(const mem_fun_eq<Atom, Atom::Element_t>&)
Firstly, am I reinventing the wheel with this predicate? Is there something in the STL that I've missed that does the same job in a single class? I can always break the predicate down into several more specific ones, but I'm trying to avoid that.
Secondly, can you help me with the compiler errors?
I don't know of any easy way to do this using the bits provided with the STL. There is probably some clever boost way, using iterator adapters, or boost::lambda, but personally I wouldn't go that way.
Obviously C++0x lambdas will make all this easy.
Your problem is attempting to cast a function like this:
const std::string&(Atom::*)()
into a function like this:
std::string (Atom::*)()
If you replace your typedef R (U::*fn_t)(); with typedef const R& (U::*fn_t)() const; then it should work.
The following avoids this problem and also provides type inference so that you can just write mem_fun_eq(&Atom::Name, atomname). It compiles for me, although I haven't tested it.
template<typename U, typename R, typename S>
class mem_fun_eq_t : public std::unary_function<U const*, bool>
{
private:
R (U::*fn_)() const;
S val_;
public:
mem_fun_eq_t(R (U::*fn )() const, S val) : fn_(fn), val_(val){}
bool operator()(U * u)
{
return (u->*fn_)() == val_;
}
};
template<typename U, typename R, typename S>
mem_fun_eq_t<U, R, S> mem_fun_eq(R (U::*fn)() const, S val)
{
return mem_fun_eq_t<U, R, S>(fn, val);
}
Have you thought of trying to mix in a mem_fun_ref or mem_fun object in place of the member function call?
Basically, you call on mem_fun to create an object that accepts two arguments T* and a template argument to the function A if it has one (or void if it doesn't). Hence you combine it like so:
template<typename MemFunc, typename CompareType, typename T>
struct MyPredicate{
MyPredicate(MemFunc _functionObj, CompareType _value)
: m_Value(_value),
m_Function(_functionObj){}
bool operator()(const T &_input){
return m_Value == m_Function(_input);
}
private:
MemFunc m_Function;
CompareType m_Value;
};
Edit:
Ok, that's not completely working so why not have:
struct NamePred: binary_function<Atom*,string,bool>{
bool operator()(Atom *_obj, string _val){
return _obj->Name() == _val;
};
};
then use bind2nd
find_if( atoms.begin(), atoms.end(), bind2nd( NamePred, "yo" ) );