After trying to make access to a storage class a little easier, I ended up in a situation that I don't have a lot of knowledge on. And, finding people that are trying to do the same thing as me isn't easy.
What I'm trying to do, is have a class that stores an array of values as strings internally, but allows simple type casting from the user's end. What I had planned on doing is use the array subscript operator to return whichever type they specify through a template. Although, it sounds a lot better than it works in practice. Here's a simple example of what I'm doing, to give you an idea of how it should work.
class StringList
{
public:
template <typename T>
T operator[](const int i)
}
From there, I would define a few specific templates, and any user could very easily define more if needed. But, the biggest problem with this is, I don't know how to call the subscript operator with a template. At first I assumed the following(which apparently isn't correct), considering it's similar to the standard way of calling a template method.
StringList list;
T var = list<T>[0];
Does anyone know the proper way of calling the subscript operator as a template? Or, should I just avoid doing this, and use a named method?
The only way calling your operator is explicitly writing list.operator[]<T>().
There are two basic ways out:
Write a function template like list.get<int>() (as proposed by templatetypedef)
Return a proxy with automatic conversation to T.
The code would look like:
// in the class
struct proxy {
proxy(StringList *list, int i) : list(list), i(i) {}
StringList *list;
int i;
template <typename T>
operator T() { return list->get<T>(i); }
};
proxy operator[](int i) { return proxy(this, i); }
template <typename T>
T get(int i) { return ...; T(); }
// how to use it:
StringList list;
int var = list.get<int>(0);
float var2 = list[0];
I think there is no syntax to pass template parameters to the natural call of operator[]. You would probably need to call:
T var = list.operator[]<T>(0);
Like you do with normal template functions, so there is no point in using operator overload here.
Related
Considering a class, Foo, I want to define an operator[] overload that is actually a template, where the return type is templated:
class Foo
{
template<typename T> T operator[](size_t i)
{
return *(reinterpret_cast<T *>(get some pointer));
}
}
This works and compiles, but I can't figure out how to use it. I don't know where to specify the type when invoking it. To provide a reference example, suppose I replace operator[] with the function name at:
class Foo
{
template<typename T> T at(size_t i)
{
return *(reinterpret_cast<T *>(get some pointer));
}
}
Then I can do something like:
Foo foo;
int myFooInt = foo.at<int>(32); // gets an int at position 32
This compiles and given an actual implementation of some kind of positioned memory provided by "get some pointer", it returns the correct value. (Note, I'm not providing any information about what "position" means, and it really doesn't matter to my question, in this case.)
But I can't figure out how/where to specify the type when using [].
By the way, the following does work:
int myFooInt = foo.operator[]<int>(32);
but something like this doesn't compile:
int myFooInt = foo[32]<int>;
nor does this:
int myFooInt = foo<int>[32];
Is what I'm trying to do even possible?
It is not possible to provide explicit template arguments for operator syntax, your foo.at(ndx) is the usual answer if you want that sort of thing.
at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.
I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.
Here is my general idea of my class definition:
class object {
public:
int first;
string second;
object(int f, string s) {
first = f;
second = s;
}
bool operator<(const object &comp) {
return first < comp.first;
}
};
This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.
Here is a short code extract from my main function:
includes ...
//code omitted
int main() {
multiset<object*> mmset;
mmset.insert(new object(10, "test"));
mmset.insert(new object(11, "test"));
return 0;
}
After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.
code extract from the stl:
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.
I would really appreciate it if someone could help me.
Best Greetings
Tom
You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.
It seems like you really just want a multiset<object>:
multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");
Now it will use < to compare the objects themselves.
If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:
auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);
Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.
Thank you for your help. That's seems to be a good solution to solve this problem.
I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :)
I will post it just as information for other seekers with the same problem.
You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content.
The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.
class object {
int first;
string second;
object() { };
object(int f, string s) {
first = f;
second = s;
}
bool operator()(const object *comp1, const object *comp2) const {
return comp1->first < comp2->first;
}
}
The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:
multiset(object*, object) mmset;
You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.
I would like to call a function on all elements of a boost::fusion::vector. The elements are of types like this:
class A {
...
void print_with_prefix(const char *prefix) {
std::cout << prefix << *this;
}
};
One can call this function on each element in this way:
// Call print_with_prefix() on a boost::fusion sequence:
struct CallPrintWithPrefix {
const char *prefix_;
CallPrintWithPrefix(const char *prefix) : prefix_(prefix) {}
template <class T> void operator()(T &element) const {
element.print_with_prefix(prefix);
}
}
template <class BoostFusionVector>
void print_all(BoostFusionVector &v, const char *prefix) {
boost::fusion::for_each(v, CallPrintWithPrefix(prefix));
}
However, this implementation of print_all() including helper class is pretty ugly and seems overly complicated! Assuming C++0x is allowed, what is the right way to implement it?
What you did is the right way. C++0x can't help much in that respect because e.g. lambda expressions are not polymorphic, so at the end of the day you'll have to write a template somewhere (which unfortunately must be at namespace scope, even with C++0x), like you did with the operator().
Some libraries like Boost.Phoenix allow to create polymorphic functors on the fly though. For instance ref(std::cout) << arg1 creates an object that is capable of passing any kind of argument to std::cout. It won't help in your case since you're calling a member function.
It's the second time I'm mentioning it today, but I do have a make_overload facility that allows me to create an overloaded functor on the fly. It could help in your case if the set of element types is small and not likely to change. For instance assuming there's only two such types A and B:
auto overload = make_overload(
[prefix](A& a)
{ a.print_with_prefix(prefix); }
, [prefix](B& c)
{ b.print_with_prefix(prefix); } );
boost::fusion::for_each(v, overload);
Could you have:
template <class T>
const T &operator[] (unsigned int x)
My thinking was if you have a map<string,string> it would be nice to have a wrapper class which lets you do:
obj["IntVal"]="12";
obj["StringVal"]="Test";
int i = obj["IntVal"];
How close to this can we actually get in C++? Is it worth the pain?
You can also do
class Class {
struct Proxy {
template<typename T> T as() { ... }
template<typename T> operator T() { return as<T>(); }
private:
Proxy(...) { ... }
Proxy(Proxy const&); // noncopyable
Proxy &operator=(Proxy const&);
friend class Class;
};
public:
Proxy operator[](std::string const& s) { ... }
};
Class a;
int i = a["foo"];
int i = a["foo"].as<int>();
T will be deduced to whatever the to be initialized object is. And you are not allowed to copy the proxy. That said, i prefer an explicit as<T> function like another one proposed too.
You can't - in:
int i = obj["IntVal"];
the actual type of T can't be inferred from the context since the return type isn't part of the function signature.
Moreover, storing integer values as strings is not considered as best practices, due to memory and performance considerations ;-)
Not worth it.
Templating the return type means you'd have to explicitly specify the template parameter when you call it. Something like this, maybe I have the syntax wrong:
int i = obj.operator[]<int>("IntVal");
C++ does not deduce template parameters from what you assign the result of the call to, only from the parameters you call the function with.
So you might as well just define a normal function:
int i = obj.get<int>("IntVal");
Or in this case, either do this or implement get using this:
int i = boost:lexical_cast<int>(obj["IntVal"]);
As Amit says, you could define operator[] to return a type which can be converted either to int or to other types. Then your example code can be made to compile without the explicit lexical_cast.
Have you looked at boost variant? Is this what you're looking for?
Well, what you wrote in your sample code doesn't match the question. Right now, you only have the return type templated.
But if you wanted to do something like:
template <class T>
const T &operator[const T& x]
that's valid, though maybe not terribly useful.
A map already provides an overloaded operator[] that does most of what you want. The thing you seem to want that's missing is implicit conversion from a string that happens to contain digits to an integer. One of the fundamental characteristics of C++ is static typing, which says that shouldn't be allowed -- so it's not. It'll be happy to do that conversion if you want, but you'll have to ask for it:
int i = lexical_cast<int>(obj["IntVal"]);
Alternatively, you could create a string-like class that supported implicit conversion to int. Personally, I'd advise against that. I don't object to implicit conversions nearly as strongly as many people do, but that still strikes me as a pretty lousy idea, at least for most general use.
right now i am learning C++, and now I know the basic concept of template,
which act just like a generic type,
and i found almost every c++ program used template,
So i really want to know when are we supposed to use template ?
Can someone conclude your experience for me about c++ template ?
When will you consider to use template ?
Supplement:
if we defined such function
template <class myType>
myType GetMax (myType a, myType b) {
return (a>b?a:b);
}
but we want to pass a object(self-defined class) for comparison, how can we implement ?
Supplement2:
in the answer below, someone have wrote this sample code
template <class myType>
const myType& GetMax (const myType& a, const myType& b) {
return (a<b?b:a);
}
template <class myType, class Compare>
const myType& GetMax (const myType& a, const myType& b, Compare compare) {
return (compare(a,b)?b:a);
}
is this correct ? can we just pass a function name as a parameter of class myType ?
G'day,
Simple answer is when you want the behaviour to remain the same independent of the type being used to instantiate the class.
So a stack of ints will behave in the same way as a stack of floats will behave as a stack of MyClass objects.
Inheritance and base classes are used when you want to allow specialisation of the behaviour.
So say you have a base class called Animal and it has a member function called makeSound(). You have no idea which sound every animal will make so you make the makeSound member function a virtual function. In fact, because there is no default sound for all animals you have no idea what to have as default behaviour so you would declare this member function as a pure virtual function.
This then tells anyone making an instance of a derived class, for example a Lion class, that they must provide an implementation the makeSound member function which will provide a roar in some way.
Edit: I forgot to add that this is one of the articles in Scott Meyers's excellent book "Effective C++" (sanitised Amazon link) which I highly recommend.
HTH
cheers,
Basically when you want to create a generic class that can handle the solution for multiple types of classes, without having to have a parent-class for all the classes you want to support.
You can just give the class along with which you want to work with (best example would be a container, which can store any type that you pass along with the creation)
//----- the container
template <class T>
class Stack
{
public:
T* stackPtr;
}
//----- example
void main()
{
typedef Stack<float> FloatStack;
typedef Stack<int> IntStack;
}
Now you can store floats and ints with the same class without having to write a specific class for each type.
Short answer: if there is no use for it: don't.
If it seems to solve a problem (code reuse on different types,...), first implement and debug without templates and then add template parameters.
Before STL/boost, they were nice to make containers.
In the example you provided, everything is OK as long as operator > is defined for the data type whose instances you're comparing.
For example, if you define the following class:
class fraction
{
private:
int _num, _den;
public:
fraction(int num, int den)
{
if (den >= 0)
{
_num = num;
_den = den;
}
else
{
_num = -num;
_den = -den;
}
}
fraction(const fraction &f)
{
_num = f._num;
_den = f._den;
}
bool operator > (const fraction &f) const
{
return (_num * f._den) > (f._num * _den);
}
bool operator == (const fraction &f) const
{
return (_num * f._den) == (f._num * _den);
}
};
Then you can use your template function with instances of this class.
int main(int argc, char* argv[])
{
fraction a(1,2); // 0.5
fraction b(3,4); // 0.75
assert(GetMax/*<fraction>*/(a,b) == a);
return 0;
}
Re: supplement. If you want to pass a comparison function, you could provide another overload:
template <class myType>
const myType& GetMax (const myType& a, const myType& b) {
return (a<b?b:a);
}
template <class myType, class Compare>
const myType& GetMax (const myType& a, const myType& b, Compare compare) {
return (compare(a,b)?b:a);
}
Samle usage: to compare C-style strings:
bool c_strings_less(const char* a, const char* b)
{
return std::strcmp(a, b) < 0; //is a less than b
}
const char* greater = GetMax("hello", "world", c_strings_less);
This is how the std::max algorithm works. (I also made a few modifications, e.g it is customary in C++ that predicates define "less-than" comparison.)
Or if you asked, how GetMax would work for arbitrary user-defined types, then those must overload operator> or your function would result in a compile error.
When you need to parameterize concept represented by a class.
For example, if you have a class that represent a way to manage a type of object
class MyThingManager
{
void add( MyThing& mything );
//...
};
...maybe you need later to use exactly the same behaviour in a new type but managing a different type. Then you have the choice to use copy/paste/replace --that would lead hell opening under your feet immediately-- or make your class have a type to manage as parametter :
template< class ThingType >
class ThingManager
{
void add( ThingType& thing );
//...
};
That way you don't duplicate code.
Another concern is when you want some function call to be compatible with any parameter that have the required semantic :
template< class MyType >
void addPi( MyType& value )
{
value += PI;
}
That way you (again) don't have to duplicate code for each types possible in parametters.
It's not called "generic programming" for nothing.
Those are simple cases, but more complex cases exists, when you want to do some meta-programming. If you want to go there, please read at least one book before writing hell code. I recommand "C++ Template Meta-Programming" for that and the excellent "Modern C++ Design" book for more advanced template usage like Policy pattern ans other well known.
Answering the second question(
but we want to pass a object(self-defined class) for comparison, how can we implement?)
If you want to use your own class in a template function using the
operator >.
Your class need only to define this operator or function.
The important part is that your class need to define the same
the operator or function the template uses.
/Tobias
if you dont know the type of your variable or you want to do same thing for many types of variables, you can use template...
if you want to add 2 int, you want to get an int for return
if you want to add 2 double, you want to get an double for return
so you use template for this..
Template provide the way to parametrize on KNOWN AT COMPILE TIME quantities. Note that it can be a type (std::vector will contain only integers) but they can also be values:
template <int N, typename T > class MyType
is templatized both on an integer and a type, and MyType<2, int> will be a different type from MyType<3, int>.
Furthermore, templates allow for Template Metaprogramming: that is the compiler executes a program at compile time. There is a fascinating example by Erwin Unruh for computing primes at compile time.
Look at http://ubiety.uwaterloo.ca/~tveldhui/papers/priority.html for a small bit of history.
It's important to note that it's perfectly alright to not write your own templates. If you're not sure why you might need them, then you probably don't need them. Templates are a very powerful tool, but they are not always the best solution.
On any common development platform, the standard library provides a high-quality implementation of many of the old-school, traditional uses of templates. Using the standard library classes and functions doesn't require writing new templates. For instance, it provides std::max(), which is the same as your example.