C++ change behavior of template methods with traits - c++

I have a template and I have the methods T get(int i) and set(int i, T val). I have to make traits class which change not behavior but the arguements which set and get have.
template<typename T,int Roz>
class Wektor{
public:
T tab[Roz];
T get(int i)
{
return tab[i];
}
void set(T val,int i)
{
tab[i]=val;
}
}
So the traits class have to change the get and set. If T is int or double we gets parametr by copy
int
int get(int i);
void set(int val,int i);
double
double get(int i);
void set(double val,int i);
for others types:
T* get(int i);
void set(T* val,int i);
That we must do in traits not by specialization of template.
So I write tratis like this:
template<typename T,int Roz>
class traitsWektor
{
public:
T tab[Roz];
T get(int i)
{
return tab[i];
}
void set(T val,int i)
{
tab[i]=val;
}
}
So here I stuck. I think i should make
template<typename T, int Roz>
class Wektor : public traitsWektor<T,Roz>
But i am not sure is that right and is still tratis.

You should separate the class template (Wektor) and the parameter type deduction:
template <class T>
struct WektorParamTraits {
typedef T const& type;
//or if you might have different types as getter return type and setter arg
typedef T const& getterReturn;
typedef T const& setterArg;
};
In that case, T is the "default" type for your getter/setter arguments. Specialize it for any type you need.
The class definition now should look like follows:
template<typename T,int Roz>
class Wektor{
T tab[Roz]; //make member variables private
public:
typename WektorParamTraits<T>::getterReturn get(int i) //const?
{
return tab[i];
}
void set(typename WektorParamTraits<T>::setterArg val,int i)
{
tab[i]=val;
}
};
Update: as was noted in the comments, you might need to define other implementations for get and set e.g. if your return type is a pointer. There are several different approaches to do that:
define functions in the traits to correctly convert between tab[i] and the argument/return value.
If it's only about pointers and non-pointers, provide two versions of the getters and setters and use std::enable_if with std::is_pointer and whatever else is needed to disable one of them.
Use the simple class definition you posted here and specialize it for the few types that don't use the usual references. Any further functionality should go into an unspecialized subclass.
Approach 2 would be very verbose and hard to read. Approach 1 would be verbose as well, and since you would delegate nearly everything except the array definition to that traits class, you could as well use approach 3 since that is not too far away.

I think this template may help you:
template<typename T>
class traits
{
public:
typedef T * result;
};
template<>
class traits<int>
{
public:
typedef int result;
};
template<>
class traits<double>
{
public:
typedef double result;
};
traits<int>::result; // is int.
traits<char>::result; // is char *.

I am not sure how you want to implement set(T*,int). But for get you might want to try this
template<typename T, size_t Roz>
class Wektor
{
public:
template<typename U=T>
typename std::enable_if<std::is_arithmetic<U>::value, U>::type
Get(size_t n)
{
return tab[n];
}
template<typename U=T>
typename std::enable_if<!std::is_arithmetic<U>::value, U*>::type
Get(size_t n)
{
return &tab[n];
}
T tab[Roz];
};

Related

template used in class involving a generic comparison function

I am trying to write a Bheap in templates and the insert function involving a generic comparison function. What is the usual way to do this? I know how to use function pointer in C. But Is there any typical C++ way to do that?
Someone told the first one, which class F could represent anything any function. But I want this function to be a comparison function which like f(T,T). While the second guy say something about the functors
template <class T, class F>class Bheap
{
public:
Bheap<T>(int allocateSize);
void insert(T value, F f);
void getMax();
private:
int sizeUsed;
int allocateSize;
vector<T> myBheap;
};
You should implement your class and the insert function, assuming whatever is passed is correct in terms of the number of arguments. If the number of arguments is not 2, the compiler will let you know.
This is the desired effect in these cases. Let the compiler detect that the function is not valid, and thus the user has to change the function to the correct requirements.
A demonstration using your code would be this:
#include <vector>
template <class T, class F>
class Bheap
{
public:
Bheap(int allocateSize) {}
void insert(T value, F f)
{
f(value, value);
}
void getMax();
private:
int sizeUsed;
int allocateSize;
std::vector<T> myBheap;
};
void SomeFunction(int, int)
{}
int main()
{
typedef void (*fn)(int, int);
Bheap<int, fn> b(10);
b.insert(10, SomeFunction);
}
You will see that this compiles and links correctly (I used a function pointer, but a functor with an overloaded operator() would also suffice).
Now if the user's function is changed to one that takes 1 argument, we get a different scenario:
#include <vector>
template <class T, class F>
class Bheap
{
public:
Bheap(int allocateSize) {}
void insert(T value, F f)
{
f(value, value);
}
void getMax();
private:
int sizeUsed;
int allocateSize;
std::vector<T> myBheap;
};
void SomeFunction(int)
{}
int main()
{
typedef void (*fn)(int);
Bheap<int, fn> b(10);
b.insert(10, SomeFunction);
}
The invalid function will make your class fail to compile. Since your template requires a 2 argument function, passing a 1 argument function via pointer causes the error (which you can see here: http://ideone.com/rT7RRa)
For function objects, here is an example of successful compilation:
http://ideone.com/yvWD5o
For unsuccessful compilation:
http://ideone.com/yjeAWB
A functor is a struct providing one or more overloads of operator (), which makes it a choice if you have several comparisons:
// Having a struct X { K key, V value };
struct Less {
template <typename K, typename V>
operator bool () (const X<K, V>& a, const X<K, V>& b> const {
return a.key < b.key;
}
template <typename K, typename V>
operator bool () (const X<K, V>& a, const K& b> const {
return a.key < b;
}
template <typename K, typename V>
operator bool () (const K& a, const X<K, V>& b> const {
return a < b.key;
}
};

Variadic template type unpacking into map keys

I'm trying to create a class which will contain a map of type_index keys mapped to pointers of each type passed as a template argument. This would allow me to specify a series of types my class will rely on in it's declaration.
I've done a bit of research but can only seem to find ways to unpack arguments, rather than types. I'm new to this subject, and would appreciate any clarification on terminology, or references to relevant text.
template <typename T>
T* SomeFakeFactoryGetter() { return new T(); }
template <class... Injected>
class UtilityProvider
{
public:
template <class U>
U* GetUtility()
{
std::type_index idx = std::type_index(typeid(U));
assert(_injectedClasses.find(idx) != _injectedClasses.end());
return reinterpret_cast<U*>(_injectedClasses[idx]);
}
// **
// How would I *unpack* all types for use as indices into my map?
// ( I realise this function is not what I want.)
template <Injected... C>
void Unpack()
{
_injectedClasses[std::type_index(typeid(C))] = SomeFakeFactoryGetter<C>();
}
private:
typedef std::unordered_map<std::type_index, void*> InjectedMap;
InjectedMap _injectedClasses;
};
class Bar{ public: void A() { printf("Hello bar"); } };
class Baz{ public: void B() { printf("Hello baz"); } };
class Nope {};
class Foo : public UtilityProvider<Bar, Baz>
{
public:
Foo()
{
GetUtility<Bar>()->A();
GetUtility<Nope>(); // Fail. User must specify which utilities this class will use.
}
};
What I've done in this situation is to create a dummy function to expand these expressions into, but it looks quite hideous:
template <int ... Dummies>
void dummy(int&& ...){}
template <class ... C>
void Unpack()
{
dummy(((_injectedClasses[std::type_index(typeid(C))] =
SomeFakeFactoryGetter<C>()), 0)...);
}
Note that in your case I think you'll be better off with using insert with an initializer_list:
template <class ... C>
void Unpack()
{
_injectedClasses.insert({std::make_pair(std::type_index(typeid(C)),
SomeFakeFactoryGetter<C>())...});
}
I couldn't find a direct mention of this but I believe there is an important difference between the two methods, in case you didn't already know. insert will not override existing key-value pairs, whereas operator[] will. This can affect which method you should use if if this is important to you.
An alternative approach:
template <typename ... C> struct Unpacker;
template <typename Tail, typename ... Queue>
struct Unpacker<Tail, Queue...>
{
void operator () (InjectedMap& injectedClasses) const
{
_injectedClasses[std::type_index(typeid(Tail))] = SomeFakeFactoryGetter<Tail>();
Unpacker<Queue...>()(injectedClasses);
}
};
template <>
struct Unpacker<>
{
void operator () (InjectedMap& injectedClasses) const {}
};

C++ - specialising member function template via templated functor does not compile

I wish to create a class that can convert between arrays of floats and doubles polymorphically. That is, the instance concerned (parameterised by <double> or <float>) and the decision to pass a float* or double* is decided at runtime, not statically.
As a proposed answer to another question, but modified according to this answer (because I understand it's not possible to fully specialise a member function template inside a class), a pure virtual base class BaseDest that provides simple overloaded member functions is sub-classed to define DestImpl<T>. I use this base class to maintain a dynamic collection of DestImpl<T> instances, with varying T. This class provides explicit overloads of the assign() member function; one for a double *, and another for a float *. The idea is that at run-time, BaseDest::assign() is called via a polymorphic pointer or reference, and this in turn calls the correct virtual assign() member function in DestImpl<T>.
Now, it is important that then the non-pointer type of the array matches T in DestImpl<T>, that a fast_copy() function is called (perhaps a memcpy), and when the types do not match a slower statically-cast-item-by-item copy is performed. So the assign() member function offloads this to a templated functor. There are two specialisations for this functor - one where the type parameter of the functor matches the type of DestImpl<T> (and therefore invokes a fast copy), and a fall-back one that catches all other cases (and invokes a slow copy).
However, I am unable to get the following code to compile. The comments show where the compiler error and warning appear - I suspect they are related. What I don't understand is why the second specialisation of apply_helper is unable to be instantiated as apply_helper<double>.
class BaseDest {
public:
virtual ~BaseDest() {}
virtual void assign(const double * v, size_t cnt) = 0;
virtual void assign(const float * v, size_t cnt) = 0;
};
template <typename T>
class DestImpl : public BaseDest {
public:
void assign(const double * v, size_t cnt) {
assign_helper<T>()(v, cnt);
}
void assign(const float * v, size_t cnt) {
assign_helper<T>()(v, cnt); // ERROR: no matching function for call to object of type 'assign_helper<double>'
}
protected:
template <typename U>
struct assign_helper {
void operator()(const U * v, size_t cnt) {
for (size_t i = 0; i < cnt; ++i) {
//slow_copy(v[i]);
}
}
};
template <typename U>
struct assign_helper<T> { // WARNING: Class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used
void operator()(const T * v, size_t cnt) {
//fast_copy(v, cnt);
}
};
};
void test() {
DestImpl<double> d; // error mentioned above appears when this is present
}
EDIT: here's something that does seem to work - moving the assign_helper struct (now a class) out of the DestImpl<T> class definition. I'm not sure this is the right way to do it, but it does seem to work so far:
// slow copy between different types
template <typename T, typename U>
class assign_helper {
public:
void operator()(const U *v, size_t cnt) {
// slow copy
}
};
// fast copy between same types
template <typename T>
class assign_helper<T, T> {
public:
void operator()(const T * v, size_t cnt) {
// fast copy
}
};
class BaseDest {
public:
virtual ~BaseDest() {}
virtual void assign(const double * v, size_t cnt) = 0;
virtual void assign(const float * v, size_t cnt) = 0;
};
template <typename T>
class DestImpl : public BaseDest {
public:
virtual void assign(const double * v, size_t cnt) {
assign_helper<T, double>()(v, cnt);
}
virtual void assign(const float * v, size_t cnt) {
assign_helper<T, float>()(v, cnt);
}
};
template <typename U>
struct assign_helper<T> { // WARNING: Class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used
The above is the cause of your error. The warning explicitly tells you that this definition will never be used. What you want instead of template < typename U > is template <>.

C++: error "explicit specialization in non-namespace scope"

template<typename T1, typename T2>
class Bimap {
public:
class Data {
private:
template<typename T> Data& set(T);
template<> Data& set<T1>(typename T1 v) { /*...*/ }
};
};
That gives me the error:
error: explicit specialization in non-namespace scope 'class Bimap<T1, T2>::Data'
I understand what the error is saying. But why I can't I do this? And how can I fix it?
One way forget templates, overload:
Data& set(T1 v) { /*...*/ }
but here is a trick which I use sometimes
you can specialize class template within class:
class {
template<typename T>
struct function_ {
static void apply(T);
};
template<>
struct function_<int> {
...
};
template<typename T>
void function(T t) { return function_<T>::apply(t); }
#Albert
I had a similar problem when I wanted to add a "trim-excess-capacity" to a custom made container. The std::vector swap trick and changing the declaration of the existing container were not valid options. So I've come up with this:
template <class T, bool isPtr> struct DeleteImp
{
static void Trim(T* to, unsigned int count);
};
template <class T> struct DeleteImp<T, false>
{
static void Trim(T* to, unsigned int count) {}
};
template <class T> struct DeleteImp<T, true>
{
static void Trim(T* to, unsigned int count)
{
for(unsigned int i=0; i<count; i++)
delete to[i];
}
};
used by my container like this:
DeleteImp<T, TypeTraits<T>::isPointer>::Trim(buf + length, truelength-length);
You may also want to check out this resource.

Template class method collides with overloaded method

I have a template class in C++ (somewhat simplified):
template<typename T>
struct C
{
T member;
void set(const &T x) { member = x; }
void set(int x) { member = x; }
};
As you can see the set() function can be called either with the type T, or with an int. This works fine unless T is an int, in which case I get an ambiguous conversion error. I understand why this is happening, but is there any way to implement what I want?
Provide a specialisation for int:
template<>
struct C<int>
{
int member;
void set(int x) { member = x };
};
?
One way around this would be to provide a specialisation of the template for int that only has one set function. Otherwise you might want to have a look at the Boost libraries if something like enable_if in their template meta programming code would allow you to turn on the function set(int x)only when T is not of type int.
could you cast the call to either int or const int in the calling code?
It depends what you're really trying to do. Your example as written doesn't make much sense as you're trying to set member, which is a T, from x, which is an int. While there are cases that may make sense I suspect in your real code you're setting something else.
Does the method have to have the same name? If so why?
Does specialising the struct for int make sense?
What other constraints do you have?
Perhaps this would work for you:
template<typename T>
struct C
{
T member;
template<typename U>
void set(const U& x) { member = x; }
void set(int x) { member = x; }
};
Now set(int) overloads set(const U&). set(const U&) accepts non T parameters, but will probably fail when you try to assign to X. It may allow more conversions than set( const T&).
If that's not good enough, adding an extra level of indirection should do the trick:
template<typename T>
struct C
{
T member;
void set(const T& x) { setInternal( x ); }
private:
template<typename U>
void setInternal(const U& x) { member = x; }
void setInternal(int x) { member = x; }
};
It appears that you want to make the set method available only if the argument is T or int. However, if you just specialize C for int, all the implicit conversions still happen, just as if you didn't attempt to treat int type in a special way at all.
If you really want to disable implicit conversions, one way is with boost::enable_if - make the method only available, if the criteria are satisfied.
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct C
{
T member;
template <class U>
typename boost::enable_if_c<
boost::is_same<T, U>::value || boost::is_same<U, int>::value
>::type
set(const U& x) { member = x; }
};
int main()
{
C<int> i;
i.set(3.14); //error
i.set(10); //OK
i.set('a'); //error
C<double> d;
d.set(3.14); //OK
d.set(3.14f); //error
d.set(10); //OK
d.set('a'); //error
}
To achieve the same result without boost::enable_if (or implementing it yourself), you might also need to make all unwanted versions of set private (C++0x also allows to delete these overloads).
template<typename T>
struct C
{
T member;
void set(const T& x) { member = x; }
void set(int x) { member = x; }
private:
template <class U>
void set(const U&);
};
template <>
struct C<int>
{
int member;
void set(int x) { member = x; }
private:
template <class U>
void set(const U&);
};
int main()
{
C<int> i;
i.set(3.14); //error
i.set(10); //OK
i.set('a'); //error
C<double> d;
d.set(3.14); //OK
d.set(3.14f); //error
d.set(10); //OK
d.set('a'); //error
}
However, making this exception for int seems rather arbitrary to me. Conversions from int might not be particularly safe, either, e.g int->float might lose precision for large values, int->short / int->char / int->unsigned might overflow.