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;
} 11 2724
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;
}
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
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.
"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.
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;
}
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
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
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
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
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
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*)(©), 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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics |
by: cppaddict |
last post by:
Hi,
I know that it is illegal in C++ to have a static pure virtual method,
but it seems something like this would be useful when the following 2
conditions hold:
1. You know that every one...
|
by: Dilip |
last post by:
Hi All
I have a pure virtual function in my base class that my derived
instances override. What are the likely causes for VC++ 7.1 to
complain of unresolved external symbol on that pure virtual...
|
by: Dmitry Prokoptsev |
last post by:
Hello,
I need to write a class for exceptions which can be thrown, caught,
stored and thrown once again. I have written the following code:
--- begin ---
#include <string>
class Exception...
|
by: nw |
last post by:
Hi,
I have three classes, a template pure virtual base class, a template
derived class and a third which I would like to use to store copies of
the derived class. The code looks like this:
...
|
by: YellowMaple |
last post by:
Is it possible to have pure virtual functions defined in a template
class? I'm trying to do something like this:
template <typename T>
class Singleton
{
public:
static T& getInstance(void)
{...
| |
by: vilarneto |
last post by:
Hello everyone,
I'm facing a particular situation about template class derivation.
The subject is old -- deriving a non-template class from a template
base class -- but my problem is that the...
|
by: Miguel Guedes |
last post by:
Hello,
I recently read an interview with Bjarne Stroustrup in which he says
that pure abstract classes should *not* contain any data. However, I
have found that at times situations are when it...
|
by: Mike -- Email Ignored |
last post by:
Is a pure virtual function in allowed in a template
base class? In any case, I have one working. Am I
skating on thin ice?
Thanks,
Mike.
|
by: Tonni Tielens |
last post by:
I'm trying to create a pure virtual class describing an interface.
Normally, when I do this I make the destructor pure virtual so that,
even if there are no members in the class, it cannot be...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
| |
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome a new...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
|
by: 6302768590 |
last post by:
Hai team
i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
|
by: muto222 |
last post by:
How can i add a mobile payment intergratation into php mysql website.
| |
by: bsmnconsultancy |
last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...
| |