Re: How: Interfacing two template methods?
On 7/5/07, t.lehmann@rtsgroup.net <t.lehmann@rtsgroup.net> wrote:
Hi,
One class is providing a template method for adding data (key, value)
storing the data internally as std::string; The name is "attributor".
Another class can store (key, variable) pairs and there's also a
template
method with the same signature as in the attributor class.
You can set a (key, value) and the relating variable will be set! (var
= value)!
Now (for any reason): I want to have an interface capable of handling
a
template method like this:
- - -
template <classT>
bool setValue(unsigned int key, const T& value);
- - -
I can't make this virtual - unfortunately! I would like to have a
concrete
implemetation - the variable mapping mechanism - and I would like to
assign the interface to the attributor. Each time 'setValue' of the
attributor
is called the 'setValue' of the interface should be called (see
example).
Is this possible to implement?
If so, how?
kindly regards
Thomas
Appendix: (example)
// this is working...
var_mapper vmapper;
int varAny1 = 0;
vmapper.registerVar(ID_ANY_1, varAny1);
vmapper.setValue(ID_ANY_1, 100);
assert(varAny1 == 100);
// also fine...
attributor att;
att.setValue(ID_ANY_1, 100);
// this is not working yet...
att.setInterface(&vmapper);
att.setValue(ID_ANY_1, 200);
assert(varAny1 == 200);
As I understand, you question could be narrowed to the one:
how to implement template virtual function?
If so, you can try to use following solution.
First of all, we declare public template function
that will call private virtual do_virtual_call:
class Foo
{
//...
private:
virtual void do_virtual_call(/*...*/);
public:
virtual ~Foo() {}
//...
template <class Ty>
void call(Ty& t);
};
There is a question, what the arguments do_virtual_call
should have. It will be one argument of type void*
(for the first time):
//...
virtual void do_virtual_call(void* type);
//...
As you guess, template argument of 'call' function will be casted to
void*. Don't blame me that it's not type safely, just read below and
see that type-safety will be preserved here.
At this moment, do_virtual_call function doesn't know what type 'void* type'
argument should be casted to. Let's resolve this issue:
class Foo
{
//...
private:
template <class Ty>
struct Proxy
{
static void foo1(void* type)
{
Ty& t = *(reinterpret_cast<Ty*>(type) );
std::cout<<"foo1 called with argument: "
<<t<<'\n';
}
static void foo2(void* type)
{
Ty& t = *(reinterpret_cast<Ty*>(type) );
std::cout<<"foo2 called with argument: "
<<t<<'\n';
}
//another functions
//...
};
protected:
typedef void (*fun_t)(void* type);
struct Pointers
{
fun_t foo1_fun;
fun_t foo2_fun;
template <class Ty>
Pointers(Proxy<Ty>)
: foo1_fun(Proxy<Ty>::foo1),
foo2_fun(Proxy<ty>::foo2)
{}
};
//...
};
As you see from the code snippet above, type information will
be "stored" in template Proxy<T> structure.
Pointers structure could be considered as
a table of different implementation of one
virtual function - do_virtual_call.
Pointers structure should be passed to do_virtual_call.
So, our first code example should be modified like this:
class Foo
{
//...
protected:
struct Pointers {/*etc...*/};
private:
virtual void do_virtual_call(const Pointers& ptrs, void* type)
{}//empty implementation in base class
public:
//...
template <class Ty>
void call(Ty& t)
{
do_virtual_call(Pointers(Proxy<Ty>() ), type);
}
};
Classes, that inherits Foo, should override do_virtual_call by simply
invoking one of the function (foo1_fun, foo2_fun) with argument type,
like this:
class MyFoo : public Foo
{
void do_virtual_call(const Pointers& ptrs, void* type)
{
ptrs.foo1_fun(type);
}
};
class YourFoo : public Foo
{
void do_virtual_call(const Pointers& ptrs, void* type)
{
ptrs.foo2_fun(type);
}
};
As you see, the "real" implementation of template virtual
function resides in base class Foo. So, if we want to add
new class to the our hierarchy, new static function should
be added to Proxy structure and Pointers constructor should
be modified. It's one of the disadvantages of described solution.
It should be mentioned that signature of the do_virtual_call
function could be easily customized according to your needs.
From sample it is clear that Proxy<T>::foo1, Proxy<T>::foo2
is static so they should be stateless. In order if virtual function
need access to Foo's members, those members should be passed to
do_virtual_call as arguments.
Below is a compilable (I hope) sample tested with
IBM's Visual Age 6 compiler:
#include <iostream>
#include <string>
class Foo
{
template <class Ty>
struct Proxy
{
static void foo1(void* type)
{
Ty& t = *(reinterpret_cast<Ty*>(type) );
std::cout<<"foo1 called with argument: "
<<t<<'\n';
}
static void foo2(void* type)
{
Ty& t = *(reinterpret_cast<Ty*>(type) );
std::cout<<"foo2 called with argument: "
<<t<<'\n';
}
};
protected:
typedef void (*fun_t)(void* type);
struct Pointers
{
fun_t foo1_fun;
fun_t foo2_fun;
template <class Ty>
Pointers(Proxy<Ty>)
: foo1_fun(Proxy<Ty>::foo1),
foo2_fun(Proxy<Ty>::foo2)
{}
};
private:
virtual void do_virtual_call(const Pointers& ptrs, void* type)
{}
public:
virtual ~Foo() {}
template <class Ty>
void call(Ty& type)
{
do_virtual_call(Pointers(Proxy<Ty>() ), &type);
}
};
class MyFoo : public Foo
{
void do_virtual_call(const Foo::Pointers& ptrs, void* type)
{
ptrs.foo1_fun(type);
}
};
class YourFoo : public Foo
{
void do_virtual_call(const Foo::Pointers& ptrs, void* type)
{
ptrs.foo2_fun(type);
}
};
int main(int argc, char** argv)
{
MyFoo my_foo;
int i = 24;
my_foo.call(i);
YourFoo your_foo;
std::string s("basic_string");
your_foo.call(s);
return 0;
}
Output should be:
foo1 called with argument: 24
foo2 called with argument: basic_string
Waiting for your comments and remarks, guys.
Regards.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]