By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,732 Members | 854 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,732 IT Pros & Developers. It's quick & easy.

pure virtual template...

P: n/a
Hi there,

I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).

Thanks for suggestions,
-Mathieu
(*)
struct Base
{
};

struct A : public Base
{
template <typename Tvoid foo() {}
};

struct B : public Base
{
template <typename Tvoid foo() {}
};

int main(int argc, char *argv[])
{
Base * base;
if( argc )
{
base = new A;
}
else
{
base = new B;
}
base->foo<int>();
return 0;
}

Oct 26 '07 #1
Share this Question
Share on Google+
11 Replies


P: n/a
On Oct 26, 2:19 pm, mathieu <mathieu.malate...@gmail.comwrote:
Hi there,

I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).
Hum...without much satisfaction here is my temporary solution.
Hopefully you guys will suggest something not involving making the
base class be polymorphic...
#include <iostream>

struct Base
{
template <typename Tvoid foo() const;
int base;
virtual void bla() {}
};

struct A : public Base
{
template <typename Tvoid foo() const { std::cout << "A" <<
std::endl; }
double a;
};

struct B : public Base
{
template <typename Tvoid foo() const { std::cout << "B" <<
std::endl; }
float b;
};

template <typename T>
void Base::foo() const
{
const A * a = dynamic_cast<const A*>(this);
const B * b = dynamic_cast<const B*>(this);
if( a ) a->foo<T>();
else if( b ) b->foo<T>();
}

int main(int argc, char *argv[])
{
Base * base;
if( argc 1 )
{
base = new A;
}
else
{
base = new B;
}
base->foo<int>();
return 0;
}

Oct 26 '07 #2

P: n/a
mathieu wrote:
Hi there,

I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).
As most compilers implement virtual method by means of virtual method tables,
declaring a template member virtual is not allowed (sorry that I cannot cite the
paragraph of the C++ standard). Were it not so, the size of the VMT table could
not be determined by the compiler (it cannot predict how many instantiations of
the template member could be needed in the following code). Thus templates and
virtual methods don't go together.
(*)
struct Base
{
};

struct A : public Base
{
template <typename Tvoid foo() {}
};

struct B : public Base
{
template <typename Tvoid foo() {}
};

int main(int argc, char *argv[])
{
Base * base;
if( argc )
{
base = new A;
}
else
{
base = new B;
}
base->foo<int>();
return 0;
}
I think you mixed up two more or less orthogonal concepts of the C++ programming
language: templates are used to reuse code where the logic is known at compile
time (that means you know exactly what your code will do when you compile the
code), whereas virtual methods are used to reuse code whose semantics will be
determined at run-time. If you know at compile time that each class A and B will
have a foo implementation with template parameter int, you may do the following:

struct Base
{
virtual void foo_int () = 0;
};

struct [A and likewise B] : public Base
{
template <typename Tvoid foo() {}
virtual void foo_int ()
{
foo<int();
}
};

int main(int argc, char *argv[])
{
:
base->foo_int();
return 0;
}

Note that there are two different resolution mechanisms involved: template
programming uses the determination with instantiation of a template function
should be used (the proper template argument is deduced), whereas virtual
methods employ a resolution mechanism involving VMTs: this table decides at
run-time which method should be invoked. You are trying to get both mechansims
working in a single step. For above mentioned reasons, this won't work.

Regards,
Stuart
Oct 26 '07 #3

P: n/a
On Oct 26, 1:49 pm, mathieu <mathieu.malate...@gmail.comwrote:
On Oct 26, 2:19 pm, mathieu <mathieu.malate...@gmail.comwrote:
Hi there,
I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).

Hum...without much satisfaction here is my temporary solution.
Hopefully you guys will suggest something not involving making the
base class be polymorphic...

I have to say, I don't really see the problem or what you're hoping to
achieve. I have a suspicion that you want to dynamically invoke a
child member function without knowing the child type. That's what
virtual functions are for. You might also take a look at some design
patterns maybe the command or visitor pattern would help. But, as I
say, I don't really get what you're after here. Maybe a little more
clarification is required.

Oct 26 '07 #4

P: n/a

"mathieu" wrote in message
Hi there,

I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).

Thanks for suggestions,
-Mathieu
Mathieu,
In The C++ Programming Language, Stroustrup (3rd ed.), in 13.6.2 (page 348),
it says:
"A member template cannot be virtual."
and there follows an explanation.
For more on virtual functions see for example:
http://www.parashift.com/c++-faq-lit...functions.html
Virtual functions are used to make a class runtime (or dynamic) polymorphic.
For a proper runtime polymorphic class you may use the NVI (NonVirtual
Interface) design pattern, see
C++ Coding Standards, Sutter & Alexandrescu.
You may also check out my runtime polymorphic integer class, see N2143 on:
http://open-std.org/jtc1/sc22/wg21/d...mailing2007-01
Of N2143 there will be a third revision in the near future.
Regards, Maarten.
Oct 26 '07 #5

P: n/a
On Oct 26, 2:49 pm, mathieu <mathieu.malate...@gmail.comwrote:
On Oct 26, 2:19 pm, mathieu <mathieu.malate...@gmail.comwrote:
Hi there,
I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).

Hum...without much satisfaction here is my temporary solution.
Hopefully you guys will suggest something not involving making the
base class be polymorphic...
Not sure exactly what you are trying to achieve, but this works well
with template classes instead of template functions.
It does use polymorphism, but that is just another way of defining an
interface:

#include <iostream>

template <typename T>
struct Base
{
virtual void foo(T x) = 0;
};

template <typename T>
struct A: Base<T>
{
void foo(T x) { std::cout << "A=" << x << "\n"; }
};

template <typename T>
struct B: Base<T>
{
void foo(T x) { std::cout << "B=" << x << "\n"; }
};

int main(int argc)
{
Base<int*base;
if (argc 1)
base = new A<int>;
else
base = new B<int>;
base->foo(45);
return 0;
}

Oct 26 '07 #6

P: n/a
On 26 oct, 19:58, "Maarten Kronenburg" <M.Kronenb...@inter.nl.net>
wrote:
"mathieu" wrote in message
Hi there,
I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).
Thanks for suggestions,
-Mathieu

Mathieu,
In The C++ Programming Language, Stroustrup (3rd ed.), in 13.6.2 (page 348),
it says:
"A member template cannot be virtual."
and there follows an explanation.
For more on virtual functions see for example:http://www.parashift.com/c++-faq-lit...functions.html
Virtual functions are used to make a class runtime (or dynamic) polymorphic.
For a proper runtime polymorphic class you may use the NVI (NonVirtual
Interface) design pattern, see
C++ Coding Standards, Sutter & Alexandrescu.
You may also check out my runtime polymorphic integer class, see N2143 on:http://open-std.org/jtc1/sc22/wg21/d...mailing2007-01
Of N2143 there will be a third revision in the near future.
Regards, Maarten.
Pretty cool ! I did not know about infinite precision integer being
proposed, that's awsome.

Thanks for the NVI info, but I don't think this is the issue here (I
am terrible at describing the issue here).

Thanks
-Mathieu

Oct 27 '07 #7

P: n/a
On 26 oct, 23:40, dvi...@gmail.com wrote:
On Oct 26, 2:49 pm, mathieu <mathieu.malate...@gmail.comwrote:
On Oct 26, 2:19 pm, mathieu <mathieu.malate...@gmail.comwrote:
Hi there,
I don't think I'll be able to describe my issue correctly, so
instead I'll just give a pseudo C++ code I am struggling with.
Basically I am looking for a 'pure virtual template' function that I
would be able to declare in the base class (*).
Hum...without much satisfaction here is my temporary solution.
Hopefully you guys will suggest something not involving making the
base class be polymorphic...

Not sure exactly what you are trying to achieve, but this works well
with template classes instead of template functions.
It does use polymorphism, but that is just another way of defining an
interface:

#include <iostream>

template <typename T>
struct Base
{
virtual void foo(T x) = 0;

};

template <typename T>
struct A: Base<T>
{
void foo(T x) { std::cout << "A=" << x << "\n"; }

};

template <typename T>
struct B: Base<T>
{
void foo(T x) { std::cout << "B=" << x << "\n"; }

};

int main(int argc)
{
Base<int*base;
if (argc 1)
base = new A<int>;
else
base = new B<int>;
base->foo(45);
return 0;

}

I can't move the template at the class level unfortunately.

Explanation:
My objects can be serialized either in big endian or little endian. So
the design is :

struct Object
{
...
void Read<Swapper>(ostream &os) { ... }
void Write<Swapper>(ostream &os) { ... }
}

Where swapper is either a no-op or actually do a byte-swap. So
template at the class level would not make much sense.

Thanks anyway,
-Mathieu

Oct 27 '07 #8

P: n/a
On Oct 27, 8:47 pm, mathieu <mathieu.malate...@gmail.comwrote:
On 26 oct, 23:40, dvi...@gmail.com wrote:
My objects can be serialized either in big endian or little endian.
Depending on what?
So
the design is :

struct Object
{
...
void Read<Swapper>(ostream &os) { ... }
void Write<Swapper>(ostream &os) { ... }
}
Where swapper is either a no-op or actually do a byte-swap. So
template at the class level would not make much sense.
I'm not sure I understand this at all. Why would you want to
swap anything. You have two output formats. If the choice is
runtime, you have to include the implementation of both in your
code. If the choice is compile time, you include one or the
other at link time. In both cases, it's pretty transparent to
the user; in the first case, you use the strategy pattern, and
the user has to specify the strategy once up front, and in the
second, it's totally transparent, since the decision is made
when you link.

And of course, you never "swap" anything. You simply write the
data in the target format.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Oct 28 '07 #9

P: n/a
On 28 oct, 10:56, James Kanze <james.ka...@gmail.comwrote:
On Oct 27, 8:47 pm, mathieu <mathieu.malate...@gmail.comwrote:
On 26 oct, 23:40, dvi...@gmail.com wrote:
My objects can be serialized either in big endian or little endian.

Depending on what?
So
the design is :
struct Object
{
...
void Read<Swapper>(ostream &os) { ... }
void Write<Swapper>(ostream &os) { ... }
}
Where swapper is either a no-op or actually do a byte-swap. So
template at the class level would not make much sense.

I'm not sure I understand this at all. Why would you want to
swap anything. You have two output formats. If the choice is
runtime, you have to include the implementation of both in your
code. If the choice is compile time, you include one or the
other at link time. In both cases, it's pretty transparent to
the user; in the first case, you use the strategy pattern, and
the user has to specify the strategy once up front, and in the
second, it's totally transparent, since the decision is made
when you link.

And of course, you never "swap" anything. You simply write the
data in the target format.
Hi James,

That is correct I have 'two' implementations (only different by one
operation: byte swapping). Thus my Object O can be written in little
or big endian. Therefore the 'endian' template parameter cannot be at
the class level (as suggested by previous poster).
Since code is cross platform, and choice is done at run-time (user
cannot know ahead of time which format he is reading) I simply pass a
'swapper' template parameter that will decide depending on file format
and architecture how to read words.

Thanks for your interest,
-Mathieu

Oct 29 '07 #10

P: n/a
On Oct 29, 2:54 pm, mathieu <mathieu.malate...@gmail.comwrote:
On 28 oct, 10:56, James Kanze <james.ka...@gmail.comwrote:
On Oct 27, 8:47 pm, mathieu <mathieu.malate...@gmail.comwrote:
On 26 oct, 23:40, dvi...@gmail.com wrote:
My objects can be serialized either in big endian or little endian.
Depending on what?
So
the design is :
struct Object
{
...
void Read<Swapper>(ostream &os) { ... }
void Write<Swapper>(ostream &os) { ... }
}
Where swapper is either a no-op or actually do a byte-swap. So
template at the class level would not make much sense.
I'm not sure I understand this at all. Why would you want to
swap anything. You have two output formats. If the choice is
runtime, you have to include the implementation of both in your
code. If the choice is compile time, you include one or the
other at link time. In both cases, it's pretty transparent to
the user; in the first case, you use the strategy pattern, and
the user has to specify the strategy once up front, and in the
second, it's totally transparent, since the decision is made
when you link.
And of course, you never "swap" anything. You simply write the
data in the target format.
That is correct I have 'two' implementations (only different by one
operation: byte swapping).
But why would you ever "swap" bytes? You write big endian, or
you write little endian. Or you write some other format---in
all cases, you have a *value* (int, whatever) which must be
output in a specified format. You convert the value to the
format, and that's it.
Thus my Object O can be written in little or big endian.
Therefore the 'endian' template parameter cannot be at the
class level (as suggested by previous poster).
Since code is cross platform, and choice is done at run-time (user
cannot know ahead of time which format he is reading) I simply pass a
'swapper' template parameter that will decide depending on file format
and architecture how to read words.
If the choice is run-time, you can't use templates. I'd go with
the strategy pattern. Something like:

class Writer
{
public:
virtual ~Writer() {}
virtual void write( std::ostream& dest, int value ) const =
0 ;
// and so on for each type.
}

class BEWriter : public Writer
{
public:
virtual void write( std::ostream& dest, int value ) const
{
uint32_t tmp = value ;
dest.put( (tmp >24) & 0xFF ) ;
dest.put( (tmp >16) & 0xFF ) ;
dest.put( (tmp > 8) & 0xFF ) ;
dest.put( (tmp ) & 0xFF ) ;
}
// and so on for each type...
} ;

class LEWriter : public Writer
{
public:
virtual void write( std::ostream& dest, int value ) const
{
uint32_t tmp = value ;
dest.put( (tmp ) & 0xFF ) ;
dest.put( (tmp > 8) & 0xFF ) ;
dest.put( (tmp >16) & 0xFF ) ;
dest.put( (tmp >24) & 0xFF ) ;
}
// and so on for each type...
} ;

You then initialize a Writer* in your output class to whichever
one is relevant, and output through it. You can even change on
the fly---first 10 integers in big endian, next 10 in little,
etc.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Oct 29 '07 #11

P: n/a
On Oct 29, 4:21 pm, James Kanze <james.ka...@gmail.comwrote:
On Oct 29, 2:54 pm, mathieu <mathieu.malate...@gmail.comwrote:
On 28 oct, 10:56, James Kanze <james.ka...@gmail.comwrote:
On Oct 27, 8:47 pm, mathieu <mathieu.malate...@gmail.comwrote:
On 26 oct, 23:40, dvi...@gmail.com wrote:
My objects can be serialized either in big endian or little endian.
Depending on what?
So
the design is :
struct Object
{
...
void Read<Swapper>(ostream &os) { ... }
void Write<Swapper>(ostream &os) { ... }
}
Where swapper is either a no-op or actually do a byte-swap. So
template at the class level would not make much sense.
I'm not sure I understand this at all. Why would you want to
swap anything. You have two output formats. If the choice is
runtime, you have to include the implementation of both in your
code. If the choice is compile time, you include one or the
other at link time. In both cases, it's pretty transparent to
the user; in the first case, you use the strategy pattern, and
the user has to specify the strategy once up front, and in the
second, it's totally transparent, since the decision is made
when you link.
And of course, you never "swap" anything. You simply write the
data in the target format.
That is correct I have 'two' implementations (only different by one
operation: byte swapping).

But why would you ever "swap" bytes? You write big endian, or
you write little endian. Or you write some other format---in
all cases, you have a *value* (int, whatever) which must be
output in a specified format. You convert the value to the
format, and that's it.
Thus my Object O can be written in little or big endian.
Therefore the 'endian' template parameter cannot be at the
class level (as suggested by previous poster).
Since code is cross platform, and choice is done at run-time (user
cannot know ahead of time which format he is reading) I simply pass a
'swapper' template parameter that will decide depending on file format
and architecture how to read words.

If the choice is run-time, you can't use templates. I'd go with
the strategy pattern. Something like:

class Writer
{
public:
virtual ~Writer() {}
virtual void write( std::ostream& dest, int value ) const =
0 ;
// and so on for each type.
}

class BEWriter : public Writer
{
public:
virtual void write( std::ostream& dest, int value ) const
{
uint32_t tmp = value ;
dest.put( (tmp >24) & 0xFF ) ;
dest.put( (tmp >16) & 0xFF ) ;
dest.put( (tmp > 8) & 0xFF ) ;
dest.put( (tmp ) & 0xFF ) ;
}
// and so on for each type...
} ;

class LEWriter : public Writer
{
public:
virtual void write( std::ostream& dest, int value ) const
{
uint32_t tmp = value ;
dest.put( (tmp ) & 0xFF ) ;
dest.put( (tmp > 8) & 0xFF ) ;
dest.put( (tmp >16) & 0xFF ) ;
dest.put( (tmp >24) & 0xFF ) ;
}
// and so on for each type...
} ;

You then initialize a Writer* in your output class to whichever
one is relevant, and output through it. You can even change on
the fly---first 10 integers in big endian, next 10 in little,
etc.
Hi James,

Thanks for taking the time to detail your solution. However I still
think that template apply in this case. I am basically doing the same,
except that I have a Swapper class that is doing the:

void DoTheIntSwap() {
(tmp ) & 0xFF ;
(tmp > 8) & 0xFF ;
(tmp >16) & 0xFF ;
(tmp >24) & 0xFF ;
}

Therefore that I can reuse code in between Reader & Writer:

http://gdcm.svn.sourceforge.net/view....h?view=markup

Finally you use -I think- the visitor pattern. I tried it and it
gives something real ugly:

http://gdcm.svn.sourceforge.net/view...97&view=markup

Basically I need to make IOSerialize of friend of every single
structure I am using in my code. Pretty ugly, heh ?
So instead each structure has access to its private member and can
easily write them. Eg.

template <typename TSwap>
IStream &Read(IStream &is)
{
is.read(ElementTag.bytes, 4);
TSwap::SwapArray(ElementTag.tags, 2); // Will expand to nothing
when writing file format match OS (e.g Big Endian file on big endian
machine)
return is;
}

template <typename TSwap>
const OStream &Write(OStream &os) const
{
uint16_t copy[2]; // local copy since function is
const
copy[0]= ElementTag.tags[0];
copy[1]= ElementTag.tags[1];
TSwap::SwapArray(copy, 2);
return os.write((char*)(&copy), 4);
}

Ref:
http://gdcm.svn.sourceforge.net/view...tion/gdcmTag.h

Thanks again for your time, this is very much appreciated as it took
me multiple iterations and I am still not entirely satisfied: template
functions in non-template classes are ugly to use :(

-Mathieu

Oct 29 '07 #12

This discussion thread is closed

Replies have been disabled for this discussion.