How to extend existing template in C++? - c++

I am working with legacy code of a template that is based on
template<class keyType, class dType> Foo Bar(const dType val)
Somewhere in that code is a place where someone made a debug function like this:
virtual void getDebugStr01(int db_id, OFCString & db_str)
{
//OFCStringStream ss;
if(db_id==0)
{
map<keyType, dType>::iterator it = m_stateData.begin();
for(;it!=m_stateData.end();it++)
{
(it->second).getDebugStr01(db_str);
}
}
}
Now, I would need to use the template class with a float. Is there anyway to do this?
Currently I get a:
error C2228: left of '.getDebugStr01' must have class/struct/union

getDebugStr01() should be a member of a class/struct. virtual methods cannot be stand alone.
You can do something like,
Foo Bar (const float f)
{
...
}

Related

gcnew operator for generic type

I have the following simple class
generic<typename T> where T:IDbConnection ref class CDbConnection
{
private:
IDbConnection^m_db;
ConnectionState^ m_originalConnState;
public:
CDbConnection();
bool Connect(String ^ connStr);
bool Exists(int id);
auto GetAllData(String^ tableStr);
~CDbConnection();
!CDbConnection();
};
and here is my constructor
generic<typename T> CDbConnection<T>::CDbConnection()
{
m_db=gcnew T();
m_originalConnState=m_db->State;
}
But the compiler complains <1> the gcnew T() can't be used for generic type
<2> auto key in use is wrong as the function expects a trailing return type
Thank you for your reading and replies
I forgot this
where T:IDbConnection, gcnew()
which is exactly the same as C# generics
to get rid of the gcnew error as stated above.
In order to achieve genericity, you must change your class definition to
generic<typename T> where T:IDbConnection ref class CDbConnection
{
private:
T m_db;
ConnectionState^ m_originalConnState;
public:
CDbConnection();
bool Connect(String ^ connStr);
bool Exists(int id);
auto GetAllData(String^ tableStr);
~CDbConnection();
!CDbConnection();
};
As you are already constraining your T to be at least IDbConnection it can't be anything else.
Then your constructor
generic<typename T> CDbConnection<T>::CDbConnection()
{
m_originalConnState=m_db.State;
}
should work like you intended.
EDIT
It seems you cannot declare a reference to a generic. If you assign the object to the stack it will work.
See this entry.
// C3229.cpp
// compile with: /clr /c
generic <class T>
ref class C {
T^ t; // C3229
};
// OK
generic <class T>
ref class D {
T u;
};

C++ template class Type being forwarded as parameter to object's template function

Ok, I don't know if the title made much sense, so I will just show the code:
template <class S,class P,class A> class Task
{
protected:
timeval start;
boost::ptr_vector<S> states;
boost::ptr_vector<P> policies;
Agent &robot;
const ACTION_MODE &a_mode;
A algo;
public:
Task(Agent &a, ACTION_MODE &m, A &alg) : robot(a), a_mode(m), algo(alg) {};
P* findPolicy(S *state);
bool stateExists(S *state);
bool if_appendState(S *state);
bool policyExists(P *policy);
bool if_appendPolicy(P *policy);
void run();
};
Class S, is for States (a polymorphic class ) class P is for policies (a templated polymoprhic class) and class A is for Algorithm classes.
For example (a class A - type):
class SarsaTD
{
protected:
const float gamma;
const float alpha;
PTYPE method;
public:
SarsaTD(float a, float g) : alpha (a), gamma (g) {method = ON_POLICY; };
template <typename P> void optimize(P *policy);
PTYPE getType();
};
I am trying to use from class Task's parameter P (policies) and forward it into a method of an instance of SarsaTD.
template <class S,class P,class A> void Task<S,P,A>::run()
{
S *state = new S(Task<S,P,A>::robot, const_cast<ACTION_MODE&>(Task<S,P,A>::a_mode));
P *policy;
if (Task<S,P,A>::if_appendState(state))
{
policy = new P(state);
Task<S,P,A>::if_appendPolicy(policy);
}
else
{
policy = Task<S,P,A>::findPolicy(const_cast<S *>(state));
policy->getValue();
delete state;
}
Task<S,P,A>::algo.optimize<P>(policy);
wb_robot_step(TIME_STEP);
}
Everythign works fine, untill the line: Task<S,P,A>::algo.optimize<P>(policy);
Where the compiler gives the following error:
task.hpp:174: error: expected-primary expression before '>'token
If I understand this correctly, the Parameter type P (policy) I use throughout the template class cannot be forwarded properly into the template function ?
Or is my syntax wrong ? Or what I am trying to do simply makes no sense ?
Task<S,P,A>::algo.optimize<P>(policy);
At that point it can't know whether optimize is a value or not. You'll understand if you just look at
Task<S,P,A>::algo.optimize < P
This not only looks like a comparison to you, but also to the compiler. Even if it then proceeds with parsing, it can't know whether your intention was a comparison or a template argument list, unless it fully instantiates the template type. If you search for "dependent name" and "two phase lookup", you'll find some useful information. The solution in your case would be manual disambiguation. Tell the compiler that optimize is a template:
Task<S,P,A>::algo.template optimize<P>(policy);
You use a template parameter in another part of the expression, try to do :
Task<S, P, A>::algo.template optimize<P>(policy)
This should work like that.

How to make this specialized function work

Here's the deal. I've looked on this forum and I didn't find the information I'm searching for or I'm probably not able to repeat it for my problem. I have a class Table which is generic and I have a class named MyString.
template <typename typeGen, int DIM>
class Table {
public:
TableauGenerique() : index_(0) { //On initialise courant à 0
}
void add(typeGen type);
private:
typeGen tableGen_[DIM];
int index_;
};
My problem is with the add function.
I sometimes have to do this in the main.cpp: (which works well)
Table <float,6> tabFloat;
tabFloat.add(1.6564);
and at one point, I need to do this which doesn't work because I need to specialize the add function to create an object of MyString, to pass it the string and then store the object in the array (tableGen) :
TableauGenerique <MyString,4> tabString;
So I tried this (after the class), without success.
template <typename typeGen, int DIM>
void Table<typeGen,DIM>::add(typeGen type){ //Which is the generic one for float or ints
if(index_ < DIM) {
tableGen_[courant_] = type;
index_++;
}
}
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type) { //(line 75) Which is the specific or specialized function for myString
MyString str(type);
if(index_ < DIM) {
tableGen_[courant_] = str;
index_++;
}
}
So, How can I make this work because it doesn't compile at all, saying: line75 : error: expected initializer before '<' token and in the main it says not matching function to call Table::add(const char[6]),
I hope everything is clear enough. Let me know if somethings is unclear.
Thank you very much for your help !
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type)
You're trying to specialize add() when in fact it is not a function template to begin with. How do you expect it to work?
You probably meant: (specialization of the class)
template <int DIM>
void Table<string,DIM>::add(string type)
But then this is allowed only if you specialize the class itself. Without specializing the class, the above code would give compilation error!
EDIT:
You can read these online tutorials:
Introduction to C++ Templates
14.5 — Class template specialization
Template Specialization and Partial Template Specialization
Explicit specialization (C++ only)
If you can control the code of the MyString class, you can provide constructors that act as implicit conversions from float to MyString. An example:
#include <string>
#include <sstream>
#include <iostream>
class MyString {
public:
MyString(float number) {
std::stringstream buffer;
buffer << number;
value = buffer.str();
}
void print() {
std::cout << value << std::endl;
}
private:
std::string value;
};
template <class T>
class Foo {
public:
void DoStuff(T item) {
item.print();
}
};
int main() {
Foo<MyString> foo;
foo.DoStuff(1.342); // implicitly converts float to MyString
return 0;
}
This way, you do not need any specialization of the add method. However, implicit conversions are tricky, and you have be careful not to invoke them accidentally, and they may create ambiguities.
EDIT: Upon a second thought, my suggestion below is basically equivalent to
Table<MyString,4> tabString;
tabString.add(MyString("whatever"));
and therefore excessive and/or does not solve the problem. Feel free to ignore :)
I would extend the class Table with a generic method to add something from which you can construct an object of the desired type:
template <typename typeGen, int DIM>
class Table {
public:
Table() : index_(0) {}
void add(typeGen type);
// The additional method
template<typename T> void add(const T& src);
private:
typeGen tableGen_[DIM];
int index_;
};
template<typename typeGen, int DIM>
template<typename T>
void Table<typeGen,DIM>::add(const T& src) {
if(index_ < DIM) {
tableGen_[courant_] = typeGen(src);
index_++;
}
}
Note construction of a temporary typeGen object before the assignment.
Assuming that MyString object can be constructed from a string literal, i.e. from const char*, you can then use it as following:
Table<MyString,4> tabString;
tabString.add("whatever");
or if the above assumption is wrong, the following should probably work (because you constructed a MyString instance from a string instance):
tabString.add(string("whatever"));

Syntax for calling templated method

I'm wondering what's the proper syntax for calling template method given as:
struct print_ch {
print_ch(char const& ch) : m_ch(ch) { }
~print_ch() { }
template<typename T>
void operator()() {
std::cout << static_cast<T>(m_ch) << std::endl;
}
private:
char m_ch;
};
I came up with sth like this:
print_ch printer('c');
printer.operator()<int>();
And it seems to work (GCC 4.5), but when I use it inside another templated method, e.g.:
struct printer {
typedef int print_type;
template<typename T_functor>
static void print(T_functor& fnct) {
fnct.operator()<print_type>();
}
};
Compilation fails with error: expected primary-expression before '>' token. Any idea to get it right? Thanks in advance.
You have to tell the compiler explicitly that the operator() of the templated fnct is itself a template:
fnct.template operator()<print_type>();
If you don't specify this with the template keyword the compiler will assume that operator() is just a normal method, not a template.
Since T_functor is itself a template, the compiler (or parser) assumes to know nothing about it's members, so you have to explicetly tell it you are calling a template methode using:
fnct.template operator()<print_type>();

error C2664 + generic classes + /Wp64

I've got the following lines of code:
p_diffuse = ShaderProperty<Vector4>(Vector4(1,1,1,1));
addProperty(&p_diffuse, "diffuse");
p_shininess = ShaderProperty<float>(10.0f);
addProperty(&p_shininess, "shininess");
the addProperty function is implemented as follows:
template <class A_Type>
void IShader<A_Type>::addProperty( ShaderProperty<A_Type>* shaderProperty,
std::string propertyName )
{
m_shaderProperties[propertyName] = shaderProperty;
}
now i get a strange compiler error on the last line of the first chunk of code. addProperty works fine in the first case, but in the second (when trying to add p_shininess) i get:
error C2664: 'IShader<A_Type>::addProperty': cannot convert parameter 1 from 'ShaderProperty<A_Type> *' to 'ShaderProperty<A_Type> *'
Huh!?
a hint of the problem could be the following: if I go to the project settings and set in the C++ general tab "check for 64-bit compatibility problems" from "no" to "yes(/Wp64)" then the error reads slightly different:
error C2664: 'IShader<A_Type>::addProperty': cannot convert parameter 1 from 'ShaderProperty<A_Type> *__w64 ' to 'ShaderProperty<A_Type> *'
what's going on?? what is __w64??
edit: class definition of IShader:
template <class A_Type> class IShader {
public:
virtual ~IShader(void) {};
virtual A_Type shade(IntersectionData* iData, Scene* scene) = 0;
protected:
ShaderProperty<A_Type>* getProperty(std::string propertyName);
void addProperty(ShaderProperty<A_Type>* shaderProperty, std::string propertyName);
private:
std::map<std::string, ShaderProperty<A_Type>*> m_shaderProperties;
};
float != Vector4. Your whole class (IShader), is templated on A_Type, not just the addProperty method. /Wp64 has nothing to do with anything. The solution to this problem will need more context, you may want to define addProperty to be a template member function instead of IShader (or in addition to) being templated.
Again this will be hard to get right without knowing exactly what you are doing, but I suspect what you want is a heterogeneous collection of properties. To do this safely you'll need to employ some runtime checking.
class ISharderProperty {
public:
virtual ~IProperty() {}
};
template<typename ShadeType>
class IShader;
template <typename T>
class ShaderProperty : public IShaderProperty {
IShader<T> *m_shader;
...
};
template<typename ShadeType>
class IShader {
ShadeType shade(...) = 0;
protected:
map<string, IShaderProperty*> m_shaderProperties;
template<typename T>
void addProperty(ShaderProperty<T>* prop, string name) {
m_shaderProperties[name] = prop;
}
template<typename T>
void getProperty(const string& name, ShaderProperty<T>** outProp) {
map<string, IShaderProperty*>::iterator i = m_shaderProperties.find(name);
*outProp = NULL;
if( i != m_shaderProperties.end() ) {
*outProp = dynamic_cast<ShaderProperty<T>*>( *i );
}
}
};
You'll have to use getProperty like
ShaderProperty<float> *x;
ashader.getProperty("floatprop", &x);
if( x ) {
...
}
Alternatively, getProperty could directly return the value, but then you'll need to mention T twice, e.g.
ShaderProperty<float> *x = ashader.getProperty<float>("floatprop");
if( x ) { ... }
You'll note I use dynamic_cast and check for NULL. If you have some other mechanism for mapping property names to property types you can use that instead and static_cast. There is some runtime overhead associated with dynamic_cast.