Templated operator[]... possible? Useful? - c++

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.

Related

C++ detect if a type can be called with a template type

I'm working on a program where some data is statically allocated and some is dynamically allocated. Now I want to have another type that can be called with any template of the type as its argument.
#include <array>
#include <vector>
template <int size> class Foo {
std::array<int, size> data;
public:
int& operator[](std::size_t idx) {return data[idx];}
};
template <> class Foo<-1> {
std::vector<int> data;
public:
int& operator[](std::size_t idx) {return data[idx];}
};
// option 1- polymorphism
struct FooCaller {
virtual void operator()(Foo data) = 0; // how would I make this work with both forms of Foo?
};
// option 2- generic programming
template <class T> concept CanCallFoo = requires (const T& t) {
t(std::declval<Foo&>()); // how do I ensure that this can call any overload of Foo?
};
Both methods would be fine, but I'm not sure how to go about this. Because the full code is more complex, I'd rather not have both Foos inherit from a base.
A callable F could write a restriction that it can be called by Foo<x> such that an arbitrary function of x must be true to be valid.
In order for your "can be called with any Foo" test to work, you would have to invert an arbitrary function at compile time.
There is no practical way to do this short of examinjng all 2^32 possible values of x. No, really. The problem you have is that the type F is possibly too powerful for you to determine its properties. This is related to Halt and Rice's theorem and the fact that template metaprogramming and C++ overload resolution is Turing complete (only related, because 2^32 is finite).
In the other case, you could type erase. Write a type RefAnyFoo/AnyFooValue that can be constructed from any Foo type and "type erases" the operations you want, like how std::function<void(int)> type erases. It could either duck type the Foo or actually restrict to instsnces of types made from the template.
Then your interface is one that takes a AnyFooValue/RefAnyFoo (depending if you are talking about copies or references).
Now, flipping this over, you can write a concept that accepts F that take RefFooAny. This isn't quite what you asked for, but plausibly you have an X/Y problem; you had a real problem, came up with incomplete solutions, then asked about how to get your solutions working, instead of the original problem.
Similarly, it is possible you only care about certain ducktype properties of Foo<?> and not the specific type. Then a concept that checks those ducktypes could be used by your callable; this again deosn't solve your problem, as much as it flips it upside down, because you cannot verify a callable accepts an entire concept from outside the callable.

Template const/non-const argument cast

I went through some searches but couldn't quite find this one. Consider this situation:
template <class T> class TemplClass;
void a_function(TemplClass<const X>&);
TemplClass<X> inst;
a_function( inst ); // fails
"invalid initialization of reference of type ‘TemplClass&’ from expression of type ‘TemplClass’"
The situation is 100% safe as far as I can tell. Still, C++ does not allow this. So I wonder what cast to use instead of the trivial C-cast.
a_function( static_cast<TemplClass<const X>&>(inst) ); // fails, similar error message
a_function( reinterpret_cast<TemplClass<const X>&>(inst) ); // works
dynamic_cast is out of the question, const_cast fails too (and rightly so).
The reinterpret_cast feels fishy (is it though?). But is there a solution with some kind of trick that I missed? Anyone know why the standard does not simply detect that this is something good? Or is there something 'bad' about this cast?
TemplClass<const T> and TemplClass<T> are unrelated types.
For example you may have (partial) specialization to make them really different:
template<typename T>
class TemplClass
{
void generic();
std::string s;
};
template<typename T>
class TemplClass<const T>
{
void foo();
std::vector<int> v;
};
Casting one into the other doesn't make sense.
In the same way
class A
{
char* p;
};
class B
{
char* p;
};
Those 2 classes are unrelated (even if it seems identical).
But is there a solution with some kind of trick that I missed?
The ideal solution is to not write such restricted template interfaces. For example, consider the standard library algorithms that take iterators to represent ranges rather than specific template types with specific object types.
If you're unable to fix the interface as it's say in a third party library, then you're going to be stuck copying your Templ<X> to a Templ<const X> before making the call.
Anyone know why the standard does not simply detect that this is
something good?
Because it's not good. The very simplest case is where there are template specializations where it would change some meaning/functionality. The compiler can't simply change the instantiation of the template.
Or is there something 'bad' about this cast?
By the language, the cast is illegal because the const and non-const template instantiations are unrelated types. Depending on the actual case, there are probably legal alternatives.

template with duck typing in C++

Is there a way to require a templates type to have properties?
For example:
template <typename T, typename U>
void foo()
{
U a,b;
bool truthiness = T()(a,b);
if (truthiness)
// do something
}
So, how would I require that T have the operator()(U a, U b) defined, that returns a specific type? Is this possible? (I know it is in d, but I'm not sure about c++).
ps. if duck typing is wrong here, let me know, I believe it is correct, but I'm not sure.
Your syntax is wrong, considering your intent. Since T is a type, T(1, 2) would construct a temporary object of type T using a two-parameter constructor. If you wanted to call Ts operator () you'd have to вo something like
T()(1, 2);
assuming a call through a temporary works for your purposes.
If T had no such operator (), the code would simply fail to compile. I'd actually say that one big benefit of template code is that it "works" as long as the syntax is valid (i.e. the very duck-typing you are talking about), i.e. there's no need to further restrict it by requiring the operator () be present.
Of course, in my example it might actually make sense, since for T = void (*)(int, int) the code would be syntactically valid, but would result in a function call through a null pointer. But again, that's specific to my version of the code, and I don't know what specific object of type T you want to apply your operator () to.
Having said that, it is worth nothing that Boost library has quite a few features that allows one to check such properties and use them for branching in template meta-programming and/or in static assertions.
By simple expressing the template then you require for T to have operator()(int, int). It will not compile if it doesn't.
However if you are creating an API and want to inform the user of the API that they have passed in an incompatible type then you need to create a type trait which detects the operator and you can specialise the function to discriminate on that fact and create a static_assert to indicate the fact.
If you have access to decltype, you can roll your own check relatively easily.
template <class T, class U> class check_same_type_t;
template <class T> class check_same_type_t<T, T> { };
template <class T, class U>
void foo()
{
U a,b;
check_same_type_t<bool, decltype(T()(a, b))> check;
bool truthiness = T()(a,b);
if (truthiness) ;
// do something
}
Which enables the following:
struct A {
bool operator()(int, int) { return true; }
};
struct B {
int operator()(int, int) { return 1; }
};
int
main()
{
foo<A, int>(); // will compile
foo<B, int>(); // won't compile
}
Just make sure that this what you really want. Forcing a generic algorithm to use a specific type may potentially come back to bite you. If a type is implicitly convertible to bool, why is it unsatisfactory to use in your condition?

C++ Array Subscript Operator Template

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.

c++ template casting

I'm a little lost in how to cast templates. I have a function foo which takes a parameter of type ParamVector<double>*. I would like to pass in a ParamVector<float>*, and I can't figure out how to overload the casting operator for my ParamVector class, and Google isn't helping me that much. Does anyone have an example of how to do this? Thanks.
EDIT: Adding some code, sorry I'm an idiot and didn't phrase the original question well at all;
template<class T> class ParamVector
{
public:
vector <T> gnome;
vector <T> data_params;
}
template<class T> class ParamVectorConsumer
{
public:
ParamVector<T> test;
}
ParamVector<float> tester;
ParamVectorConsumer<double> cons;
cons.ParamVector = tester
will fail to compile. I would like to know how to write it so that I can cast the float version of tester to a ParamVector double. Thanks
EDIT2: Casting was the wrong word. I don't mind writing extra code, I just need to know how to get this to be accepted by the compiler so that I can write some sort of conversion code.
I'm not sure but maybe you need some like this:
template< typename TypeT >
struct ParamVector
{
template < typename NewTypeT >
operator ParamVector< NewTypeT >()
{
ParamVector< NewTypeT > result;
// do some converion things
return result;
}
template< typename NewTypeT >
ParamVector( const ParamVector< NewTypeT > &rhs )
{
// convert
}
template < typename NewTypeT >
ParamVector& operator=( const ParamVector< NewTypeT > &rhs )
{
// do some conversion thigns
return *this;
}
};
ParamVector< double > d1;
ParamVector< float > f1;
f1 = d1;
You can choose use conversion operator or operator= - I've provided both in my example.
Well, you can't. Each different actual template parameter, makes an entirely new class, which has no* relation inheritance relation with any any other class, with a diffent actual argument, made from that template.
No relationship. Well, except that each provides the same interface, so that inside a template you can handle then the same.
But neither the static types or the dynamic types have any relation.
Let me drop back here, and explain.
When I declare a pointer to classtype, like
Foo fp*;
fp has what we call a static type, of pointer-to Foo. If class Bar is a subclass of Foo, and I point fp at new Bar:
fp = new Bar1();
then we say that the object pointed to by fp has the dynamic type of Bar.
if Bar2 also publicly derives from Foo, I can do this:
fp = new Bar2();
and without ever even knowing what fp points to, I can call virtual methods declared in Foo, and have the compiler make sure that the method defined in he dynamic type pointed to is what's called.
For a template< typename T > struct Baz { void doSomething(); };
Baz<int> and Baz<float> are two entirely different class types, with no relationship.
The only "relationship" is that I can call doSomething() on both, but since the static types have no relationship, if I have a Baz<int> bi*, I can't point it to a Baz<float>. Not even with a cast. The compiler has no way to "translate" a call to the Baz doSotheing method into a call to a Baz::doSomething() method. That's because there is no "Baz method", there is no Baz, there are ony Baz<int>s and Baz<float>s, and Baz<whatevers>, but there's no common parent. Baz is not a class, Baz is a template, a set of instructions about how to make a class if and only if we have a T parameter that's bound to an actual type (or to a constant).
Now there is one way I can treat those Bazes alike: in a template, they present the same interface, and the compiler, if it knows what kind of Baz we're really dealing with, can make a static call to that method (or a static access of a member variable).
But a template is not code, a template is meta-code, the instructions of how to synthesize a class. A "call" in a template is not a call,it's an instruction of how to write the code to make a call.
So. That was long winded and confusing. Outside of a template definition, there is no relationship between a ParamVector and aParamVector. So your assignment can't work.
Well. Almost.
Actually, with partial application of templates, you can write a template function which gives a "recipe" of how to transform a Paramvector<T> to a ParamVector<U>. Notice the T and the U. If you can write code to turn any kind of ParamVector, regardless of actual template parameter into any other kind of ParamVector, you can package that up as a partially applied template, and the compiler will add that function to, for example, ParamVector.
That probably involves making a ParamVector<U>, and transforming each T in the ParamVector<T> into a U to put in the ParamVector<U>. Which still won't let you asign to a ParamConsumer<T>.
So maybe you want to have both templates and inheritance. In that case, you can same that all ParamVectors regardless of type inherit from some non-template class. And then there would be a relationship between ParamVectors, they'd all be sibling subclasses of that base class.
Notice that when you do an implicit cast, what the compiler can do without your help (I mean, without additional code) is just reference-upcast. That means that, seeing the object as a reference (for cast purposes only, the nature of the object doesn't change of course), it can look at it as one of its ancestors. When you have two template instances, none of them is an ancestor of the other (neither they are necessarily in the same hierarchy).
After trying that, the compiler looks for cast operators, constructors, etc. At this stage, probably a temporary object needs to be created, except when you're doing attribution and there's an attribution operator that fits.
One solution to your problem would be to use a conversion constructor:
template<class T> class ParamVector
{
public:
vector <T> gnome;
vector <T> data_params;
ParamVector()
{
}
template <class T2> ParamVector(const ParamVector<T2> &source)
{
gnome.reserve(source.gnome.size());
copy(source.gnome.begin(), source.gnome.end(), gnome.begin());
data_params.reserve(source.data_params.size());
copy(source.data_params.begin(), source.data_params.end(), data_params.begin());
}
};
This would create a temporary object whenever you use an instance of the template and other is required. Not a good solution if you're dealing with large containers, the overhead isn't acceptable. Also, if you pass a template instance to a function that requires not an object but a reference, the compiler won't call the conversion constructor automatically (you have to do an explicit call).
You are lost because you can't do it - the two types are completely different. Whenever you come across the need for a cast in your code, you should examine both your code and your design very closely - one or both is probably wrong.
You can't do this with a direct cast because double and float are completly different sizes. Doubles are going to be 64 bits while floats are 32. A pointer forced to cast from a
ParamVector<float>
to
ParamVector<double>
is going to misinterpret the data and give you garbage. You may want to google "pointer aliasing" or just learn more about pointers in general to see how this isn't going to work.
Think about it for a second you have one array that is a bunch of 64 bit values with fields layed out like this
0 => abcdabcd12341234
1 => abcdabcd12341234
If you force this to be interpreted as an array of 32 bit values, its going to not be interpreted correctly. You may or may not get something like
0 => abcdabcd
1 => 12341234
2 => abcdabcd
3 => abcdabcd
or it could be switched so that the 12341234's come first, or something stranger due to how the word ordering works out.
You mentioned "template casting" in your headline, so I'll presume that ParamVector is a templated type. That means that foo could be templated as well, and that would solve your problem.
template <typename T>
void foo(ParamVector<T> const& data)
{
}
You can't cast templates like this because the types are unrelated.
However, you can add a conversion function, such as:
(Your code wasn't really complete, so I can post complete code either. Hopefully you will get the idea.)
template<class T> class ParamVectorConsumer
{
public:
ParamVector<T> test;
template<T2> ParamVectorConsumer<T2> convert()
{
ParamVectorConsumer<T2> ret;
ret = this->...
}