473,383 Members | 1,859 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Design Problem: "Smart Paramaters"

Here is a design problem I ran into this am - and I have cleaned the
bathroom,
scrubbed toilet sink and tub, windexed all glass, mopped the floor, and
vacuumed the house - no dice, the problem is still there. Maybe y'all have
some ideas?

Background
==========

The basic idea behind templates, of course, is that much code is independent
of the data types it works on: the basic operations of a doubly linked list,
for example, are identical whether it is a list of donuts or a list of cops.
Rather than duplicate the code for each list of items of type T we just
create a template for all lists independently of type by writing the list
in terms of a template argument: template<typename T> class DList, using T
wherever we normally would use a specific concrete data type - we let the
compiler duplicate the code. So far so good (ignoring "code bloat" issues
here).

But in truth we do not always want the code *entirely* independent of the
types it works on. A case in point is how we pass read-only paramaters to
functions (and to member functions). For "big" types (or types that are
expensive to construct) we want to pass a const reference, for other types
we would prefer to pass them by value - more efficient that way. So the
only difference, in this scenario, is how we declare function arguments.

A Solution?
===========
Vandervoode and Josuttis discuss, in C++ Templates: The Complete Guide, a
way out. My (very simple and nearly verbatim copied) implimentation is:

template<typename T>
class TROM
{
public:
typedef typename IfElse< sizeof(T) <= 2 * sizeof(void *),
T,
T const&>::Type Type;
};

Where IfElse is a "type function" that "returns" its second argument if the
first argument evaluates to true, its third argument otherwise:

template<bool C, typename T1, typename T2> class IfElse;
template<typename T1, typename T2> class IfElse<true, T1, T2>
{ public: typedef T1 Type; };
template<typename T1, typename T2> class IfElse<false, T1, T2>
{ public: typedef T2 Type; };

Now, I know TROM is naive in that a class or struct might be "small" yet
expensive to construct - that is not the issue here.

The Problem
===========
The prolem arises when some member functions of a class take instances of
the class itself as arguments:

struct XTest
{
unsigned int x;
void DoOr(typename TROM<XTest>::Type src) {x |= src.x;}
};

This fails to compile:
....
/usr/home/olea/binfosys/operations/base/include/binfosys/trom.h:44: `sizeof'
applied to incomplete type `XTest'

In this particular case I don't need TROM to tell me to pass XTest by value,
not by const reference, but if instead of "unsigned int" I use type T I do
need it:

template <typename T>
struct XTest
{
T x;
void DoOr(typename TROM<XTest<T> >::Type src) {x |= src.x;}
};

Any ideas?

Thanks for your consideration - Michael

ps:
tayfun.2wire.net.olea (118) g++ -v
Using built-in specs.
Configured with: FreeBSD/i386 system compiler
Thread model: posix
gcc version 3.2.2 [FreeBSD] 20030205 (release)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Jul 23 '05 #1
5 1626

Just add parameter, describing your class to TROM:

// T -- parameter type
// C -- our class type
template<class T,class C>
class TROM {
typedef typename IfElse< sizeof(T) <= 2 * sizeof(void *),
T,
T const&>::Type Type;
};

// and if type of parameter and type of our class is equal -- result is
// reference to class
template<typename C>
class TROM<C,C>
{
public:
typedef C& Type;
};
Jul 23 '05 #2
Manvel Avetisian wrote:

Just add parameter, describing your class to TROM:

// T -- parameter type
// C -- our class type
template<class T,class C>
class TROM {
typedef typename IfElse< sizeof(T) <= 2 * sizeof(void *),
T,
T const&>::Type
Type;
};

// and if type of parameter and type of our class is equal -- result is
// reference to class
template<typename C>
class TROM<C,C>
{
public:
typedef C& Type;
};


I don't think I described the problem very clearly last night, but this
reply did give me an idea for a work-around:

//
// TCROM: A workaround version of TROM for the special case of classes
// that have member functions that take instances of themselves as
// arguments: class X { ... void Foo(const X&); ...}; - call by referene,
// or class X { ... void Foo(X); ...}; - call by value. The problem with
// using TROM in this case: void Foo(typename TROM<X>::Type) is that at
// this point X is an "incomplete type", and the sizeof test above fails.
// The solution here is to pass TCROM a "storage type" T, which is a
complete
// type, and the class type C. If T is small then we "return" C, otherwise
// we return C const&.
//
template<typename T, class C>
class TCROM
{
public:
typedef typename IfElse< sizeof(T) <= 2 * sizeof(void *),
C,
C const&>::Type Type;
};

Jul 23 '05 #3
Michael Olea wrote:
template<typename T>
class TROM
{
public:
typedef typename IfElse< sizeof(T) <= 2 * sizeof(void *),
T,
T const&>::Type Type;
};
....
template<bool C, typename T1, typename T2> class IfElse;
template<typename T1, typename T2> class IfElse<true, T1, T2>
{ public: typedef T1 Type; };
template<typename T1, typename T2> class IfElse<false, T1, T2>
{ public: typedef T2 Type; };
....
template <typename T>
struct XTest
{
T x;
void DoOr(typename TROM<XTest<T> >::Type src) {x |= src.x;}
};

Any ideas?


Well, to take the size of "XTest<T>" (which "TROM<XTest<T> >" does), the
compiler has to instantiate the template "XTest<T>". Since instantiating
"XTest<T>" requires knowing (taking) the size of "XTest<T>" that's
infinite recursion - even if you rewrite it so that the "incomplete
type" error goes away (*a).
So you can only use the size of something else.

You could add an additional template parameter that tells the template
whether to use references to itself or copies or automatically decide
what to use. The first two versions can be implemented whithout
recursion, and the "auto" version could e.g. use the size of the "by
reference" version to decide what parameter-type to use.

---

*a: Which is possible by adding a "static const MySize" in "XTest<T>"
and make "TROM" use "T::MySize" instead of "sizeof(T)". The code would
look like the following, which also makes the recursion pretty clear:

template<typename T>
class TROM
{
public:
typedef typename IfElse< T::MySize <= 2 * sizeof(void *),
....
template <typename T, size_t S = sizeof(XTest<T>)>
struct XTest
{
static const MySize = S;
....

Here you could break the recursion by changing "size_t S =
sizeof(XTest<T>)" to "size_t S = sizeof(XTest<T,0>)" which should have
the effect that the size of the "by-value" version is used to decide
which version to instantiate.

bye, Paul
Jul 23 '05 #4
On 6 Jun 2005 05:25:24 -0400, Michael Olea wrote:

This fails to compile:
...
/usr/home/olea/binfosys/operations/base/include/binfosys/trom.h:44: `sizeof'
applied to incomplete type `XTest'

In this particular case I don't need TROM to tell me to pass XTest by value,
not by const reference, but if instead of "unsigned int" I use type T I do
need it:

template <typename T>
struct XTest
{
T x;
void DoOr(typename TROM<XTest<T> >::Type src) {x |= src.x;}
};

Any ideas?

Since you're using TROM to select the function parameter type based on
the size of XTest<T> (which doesn't work because the size of XTest<T> is
unknown until the compiler comes to the end of the class definition
(during instantiation)), you can instead pass the size of XTest<T>
member x to a NewTROM template

template<typename T, size_t size>
class NewTROM
{
public:
typedef typename IfElse< size <= 2 * sizeof(void *),
T,
T const&>::Type Type;
};
void DoOr(typename TROM<XTest<T>,sizeof(x) >::Type src) {x |= src.x;}

because in this case, you know roughly how to calculate the size of
XTest<T>.
A couple of things to note : member functions of a class can have a
parameter type that is an incomplete class only if the class in question
is the class the function is a member of. Data members of a class
cannot have zero size even if their type is an empty class. You might
have to calculate an amount to allow for packing.

To overcome the unknown packing size allowance, you can create a "mirror
class" and use that to get the size i.e.
template <typename T>
struct XTestMirror
{
T x;
};

void DoOr(typename TROM<XTest<T>,sizeof(XTestMirror<T>) >::Type src)
{x |= src.x;}

and hope that the mirror class has the same size as its counterpart.
With some effort, you may be able to automatically check that
sizeof(XTest<T>) is the same as sizeof(XTestMirror<T>) e.g. by using a
static data member of XTest<T> whose definition follows the XTest class
and whose initializer uses sizeof(XTest<T>) == sizeof(XTestMirror<T>) in
a way that causes a compile time error if not equal.

Graeme
Jul 23 '05 #5
Graeme Prentice wrote:
On 6 Jun 2005 05:25:24 -0400, Michael Olea wrote:

This fails to compile:
...
/usr/home/olea/binfosys/operations/base/include/binfosys/trom.h:44:
`sizeof'
applied to incomplete type `XTest'

In this particular case I don't need TROM to tell me to pass XTest by
value, not by const reference, but if instead of "unsigned int" I use type
T I do need it:

template <typename T>
struct XTest
{
T x;
void DoOr(typename TROM<XTest<T> >::Type src) {x |= src.x;}
};

Any ideas?

Since you're using TROM to select the function parameter type based on
the size of XTest<T> (which doesn't work because the size of XTest<T> is
unknown until the compiler comes to the end of the class definition
(during instantiation)), you can instead pass the size of XTest<T>
member x to a NewTROM template

template<typename T, size_t size>
class NewTROM
{
public:
typedef typename IfElse< size <= 2 * sizeof(void *),
T,
T const&>::Type Type;
};
void DoOr(typename TROM<XTest<T>,sizeof(x) >::Type src) {x |= src.x;}

because in this case, you know roughly how to calculate the size of
XTest<T>.
A couple of things to note : member functions of a class can have a
parameter type that is an incomplete class only if the class in question
is the class the function is a member of. Data members of a class
cannot have zero size even if their type is an empty class. You might
have to calculate an amount to allow for packing.

To overcome the unknown packing size allowance, you can create a "mirror
class" and use that to get the size i.e.
template <typename T>
struct XTestMirror
{
T x;
};

void DoOr(typename TROM<XTest<T>,sizeof(XTestMirror<T>) >::Type src)
{x |= src.x;}

and hope that the mirror class has the same size as its counterpart.
With some effort, you may be able to automatically check that
sizeof(XTest<T>) is the same as sizeof(XTestMirror<T>) e.g. by using a
static data member of XTest<T> whose definition follows the XTest class
and whose initializer uses sizeof(XTest<T>) == sizeof(XTestMirror<T>) in
a way that causes a compile time error if not equal.

Graeme


Thanks for the suggestions. NewTROM is similar to what I ended up doing:

template<typename T, class C>
class TCROM
{
public:
typedef typename IfElse< sizeof(T) <= 2 * sizeof(void *),
C,
C const&>::Type Type;
};

The idea is that T is a "storage type" for C. I'll have to look more closely
at the "unknown packing" issues. I was assuming that given:

template<typename A, typename B, typename C...>
struct Store
{
A anA;
B aB;
C aC;
...
};

template<typename A, typename B, typename C...>
class X
{
Store<A,B,C...> myStorage;
};

that sizeof(Store<A,B,C...>) would equal sizeof(X<A,B,C...>)
but I suppose that need not be the case.

Thanks again for the comments.
- Michael

Jul 23 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Martin Goldman | last post by:
Hello all, I've been struggling for a few days with the question of how to convert "smart" (curly) quotes into straight quotes. I tried playing with the htmlentities() function, but all that is...
2
by: Tim Hochberg | last post by:
During the recent, massive, painful Lisp-Python crossposting thread the evils of Python's whitespace based indentation were once again brought to light. Since Python' syntax is so incredibly...
14
by: David B. Held | last post by:
I wanted to post this proposal on c.l.c++.m, but my news server apparently does not support that group any more. I propose a new class of exception safety known as the "smart guarantee". ...
2
by: Chris Lau | last post by:
What is the best way to compare two entries in a single table where the two fields are "almost" the same? For example, I would like to write a query that would compare the first two words in a...
11
by: Ron | last post by:
Hello, I'm having an aggravating time getting the "html" spewed by Word 2003 to display correctly in a webpage. The situation here is that the people creating the documents only know Word, and...
2
by: BobAchgill | last post by:
Is there a way to let the User click on a button on a web site and have that download and install my prepackaged compressed data directory and place it nicely under my existing VB .Net Form...
3
by: red floyd | last post by:
I've got some code where somebody cut&pasted some comments from MS Word, and so these comments have "smart quotes" (in particular apostrophes) embedded. The apostrophe is character hex 0x92. ...
5
by: Noozer | last post by:
I'm looking for a "smart folder" program to run on my Windows XP machine. I'm not having any luck finding it and think the logic behind the program is pretty simple, but I'm not sure how I'd...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 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 former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.