template functions and "return type overloading"

A

Ann Huxtable

I have the following code segment - which compiles fine. I'm just
worried I may get run time probs - because it looks like the functions
are being overloaded by the return types?. Is this Ok: ?

template <class T1, class T2>
int getValue( T1 col, T2 row ) ;

template <class T1, class T2>
double getValue( T1 col, T2 row ) ;

template <class T1, class T2>
std::string getValue( T1 col, T2 row ) ;

template <class T1, class T2>
Table getValue( T1 col, T2 row ) ;

.... etc.
 
J

Jonathan Mcdougall

Ann said:
I have the following code segment - which compiles fine. I'm just

It shouldn't. You cannot overload functions on their return value only:

template <class T1, class T2>
int getValue( T1 col, T2 row ) ;

template <class T1, class T2>
double getValue( T1 col, T2 row ) ;

int main()
{
int a = getValue(1, 2);
}

"ComeauTest.c", line 9: error: more than one instance of overloaded
function
"getValue" matches the argument list, the choices that match
are:
function template "getValue(T1, T2)"
function template "getValue(T1, T2)"
The argument types that you used are: (int, int)
int a = getValue(1, 2);

It will compile until you try to call one of the overloads.
worried I may get run time probs - because it looks like the functions
are being overloaded by the return types?. Is this Ok: ?
No.

template <class T1, class T2>
int getValue( T1 col, T2 row ) ;

template <class T1, class T2>
double getValue( T1 col, T2 row ) ;

template <class T1, class T2>
std::string getValue( T1 col, T2 row ) ;

template <class T1, class T2>
Table getValue( T1 col, T2 row ) ;

... etc.

What are you trying to achieve?


Jonathan
 
B

benben

I have the following code segment - which compiles fine. I'm just
worried I may get run time probs - because it looks like the functions
are being overloaded by the return types?. Is this Ok: ?

template <class T1, class T2>
int getValue( T1 col, T2 row ) ;

template <class T1, class T2>
double getValue( T1 col, T2 row ) ;

template <class T1, class T2>
std::string getValue( T1 col, T2 row ) ;

template <class T1, class T2>
Table getValue( T1 col, T2 row ) ;

... etc.

Hmm, I must say I am surprised that these declarations compile. But bear in
mind there are all but template declaration nevertheless. The compiler won't
issue any error until it has to instantiate the template, such as an
explicit template instantiation or a call to the function template:

template int getValue(int, int); // error
int a = getValue(1,2); // error

Regards,
Ben
 
A

Ann Huxtable

Jonathan said:
It shouldn't. You cannot overload functions on their return value only:

template <class T1, class T2>
int getValue( T1 col, T2 row ) ;

template <class T1, class T2>
double getValue( T1 col, T2 row ) ;

int main()
{
int a = getValue(1, 2);
}

"ComeauTest.c", line 9: error: more than one instance of overloaded
function
"getValue" matches the argument list, the choices that match
are:
function template "getValue(T1, T2)"
function template "getValue(T1, T2)"
The argument types that you used are: (int, int)
int a = getValue(1, 2);

It will compile until you try to call one of the overloads.




What are you trying to achieve?


Jonathan

I'm writing a "Table" class which mimics a table returned in an SQL
query. The only difference is that in my table, I want to be able to
nest tables within tables - so some columns will contain other table.

To answer your question regarding whT i'm trying to achieve, the
templated functions above are retriving the values stored in a cell. The
cell is currently implemented as a union (although I may change to the
Boost variant type at a later stage). The cell can store one of the
following types:

char*
int,
double
void * //To allow nesting


Cells are referenced by (row,col) where each of the parameters could
either be a string (name) or int (index). This permutated with the large
number of possible return variables will result in 4*4 = 16 functions
just to get a value, and then another 16 to set a value - and this is
not easily extensible if I need to store other variable types. Hence my
post.

If you have any ideas as to how to solve this problem, I'd be willing to
hear them. Tks
 
J

Jonathan Mcdougall

Ann said:
I'm writing a "Table" class which mimics a table returned in an SQL
query. The only difference is that in my table, I want to be able to
nest tables within tables - so some columns will contain other table.

To answer your question regarding whT i'm trying to achieve, the
templated functions above are retriving the values stored in a cell. The
cell is currently implemented as a union (although I may change to the
Boost variant type at a later stage). The cell can store one of the
following types:

char*
int,
double
void * //To allow nesting


Cells are referenced by (row,col) where each of the parameters could
either be a string (name) or int (index). This permutated with the large
number of possible return variables will result in 4*4 = 16 functions
just to get a value, and then another 16 to set a value - and this is
not easily extensible if I need to store other variable types. Hence my
post.

If you have any ideas as to how to solve this problem, I'd be willing to
hear them. Tks

Include the return in the template list:

#include <string>
#include <sstream>

template <class Ret, class T1, class T2>
Ret getValue(T1 col, T2 row)
{
std::string value = get_value_from_db_as_string(col, row);

std::istringstream iss(value);
Ret r = Ret();

iss >> r;

return r;
}

int main()
{
int a = getValue<int>(10, 10);
double b = getValue<double>(11, 11);
Image c(getValue<Image>(12, 12)); // provided Image overloaded the
operator>>
}

If you cannot get the value as a string from the database, you'll have
to find another way. Come back if you didn't find any.


Jonathan
 
A

Ann Huxtable

Jonathan said:
Include the return in the template list:

#include <string>
#include <sstream>

template <class Ret, class T1, class T2>
Ret getValue(T1 col, T2 row)
{
std::string value = get_value_from_db_as_string(col, row);

std::istringstream iss(value);
Ret r = Ret();

iss >> r;

return r;
}

int main()
{
int a = getValue<int>(10, 10);
double b = getValue<double>(11, 11);
Image c(getValue<Image>(12, 12)); // provided Image overloaded the
operator>>
}

If you cannot get the value as a string from the database, you'll have
to find another way. Come back if you didn't find any.


Jonathan

The database example I gave was just a conceptul illustration. I will
not necesarily be loading data from a db. I think the simplest
implementation would be to create templated functions (for each of the
data types supported - i.e. getString(), getLong(), getNestedTable() etc.

Thanks for your help nonetheless ..
 
B

benben

Ann Huxtable said:
I'm writing a "Table" class which mimics a table returned in an SQL
query. The only difference is that in my table, I want to be able to
nest tables within tables - so some columns will contain other table.

To answer your question regarding whT i'm trying to achieve, the
templated functions above are retriving the values stored in a cell. The
cell is currently implemented as a union (although I may change to the
Boost variant type at a later stage). The cell can store one of the
following types:

char*
int,
double
void * //To allow nesting


Cells are referenced by (row,col) where each of the parameters could
either be a string (name) or int (index). This permutated with the large
number of possible return variables will result in 4*4 = 16 functions
just to get a value, and then another 16 to set a value - and this is
not easily extensible if I need to store other variable types. Hence my
post.

If you have any ideas as to how to solve this problem, I'd be willing to
hear them. Tks

Now, what you described is indeed three problems: input types, output types,
and extensibility. Let's take them apart:

You are looking for int-int, int-string, string-int, string-string pairs as
input type and are looking for extensibility, if I correctly understand your
post. The ideal way is to use the C++ type system to help you. What's in my
mind is a single concept for locating a cell, say, cell_entry:

class cell_entry_base
{
protected:
cell_entry_base();
// whatever you need to know to locate a cell
};

// map to col-row pair types
template <typename ColT, typename RowT>
class cell_entry;

// specialize for <int, int>
template <> class cell_entry<int, int>: public cell_entry_base
{
//...
};

// also specialize for <int, string>, <string, int> and <string, string>
//...

// also specialize for other types you wish, extending made easy...

Now the output type. You need to map a set of C++ type to the internal types
supported by the database, if I am still on the track. So I came up with
traits:

template <typename T>
class entry_type_trait;

template <> class entry_type_trait<char*>
{
public:
static char* get_value(cell_entry_base&) throw (bad_type)
{
// your database access code here,
// throw bad_type if type not matched
}

//... more ops up to you
};

// also specialize for <int> <double> and <void*>
// ...

Note that you only have to add a new specialization to extend the type
mapping. And finally the function getValue can be trivially implemented:

template <typename ReturnT, typename ColT, typename RowT>
ReturnT getValue(ColT col, RowT row) throw (bad_type)
{
cell_entry<ColT, RowT> entry(col, row); // enforce input types
return entry_type_trait<ReturnT>::get_value(entry); // output
types
}



Regards,
Ben
 
A

Ann Huxtable

benben said:
Now, what you described is indeed three problems: input types, output types,
and extensibility. Let's take them apart:

You are looking for int-int, int-string, string-int, string-string pairs as
input type and are looking for extensibility, if I correctly understand your
post. The ideal way is to use the C++ type system to help you. What's in my
mind is a single concept for locating a cell, say, cell_entry:

class cell_entry_base
{
protected:
cell_entry_base();
// whatever you need to know to locate a cell
};

// map to col-row pair types
template <typename ColT, typename RowT>
class cell_entry;

// specialize for <int, int>
template <> class cell_entry<int, int>: public cell_entry_base
{
//...
};

// also specialize for <int, string>, <string, int> and <string, string>
//...

// also specialize for other types you wish, extending made easy...

Now the output type. You need to map a set of C++ type to the internal types
supported by the database, if I am still on the track. So I came up with
traits:

template <typename T>
class entry_type_trait;

template <> class entry_type_trait<char*>
{
public:
static char* get_value(cell_entry_base&) throw (bad_type)
{
// your database access code here,
// throw bad_type if type not matched
}

//... more ops up to you
};

// also specialize for <int> <double> and <void*>
// ...

Note that you only have to add a new specialization to extend the type
mapping. And finally the function getValue can be trivially implemented:

template <typename ReturnT, typename ColT, typename RowT>
ReturnT getValue(ColT col, RowT row) throw (bad_type)
{
cell_entry<ColT, RowT> entry(col, row); // enforce input types
return entry_type_trait<ReturnT>::get_value(entry); // output
types
}



Regards,
Ben

Ok, this looks interesting, I'm re-reading your post to make sure I
understand it completely (BTW, I believe you are on the right track -
i.e. you *did understand the problem posed). If I encounter any probs
with your solution, I'll be right back. tks
 
A

Ann Huxtable

Ann said:
Ok, this looks interesting, I'm re-reading your post to make sure I
understand it completely (BTW, I believe you are on the right track -
i.e. you *did understand the problem posed). If I encounter any probs
with your solution, I'll be right back. tks

This is quite an elegant approach (albeit a bit confusing - to me
atleast). You may hev been also led slight astray by the special case of
loading data from a database into this memory table - however, the
proposed implimentation is still apropriate nonetheless.

Would you care to elaborate exactly what the base class cell_entry_base
does (you noted: // whatever you need to know to locate a cell). I'd
also be grateful if you add a little more flesh (or at least comments to
the template specializations for class cell_entry). It is likely that I
may have to come back to you several times during my implementation - I
hope you don't mind :) (please indicate if you are too busy to assist
- though, in which case I'll keep it simple and use my less elegant
method - but I really like this more compact approach...)
 
B

benben

This is quite an elegant approach (albeit a bit confusing - to me
atleast). You may hev been also led slight astray by the special case of
loading data from a database into this memory table - however, the
proposed implimentation is still apropriate nonetheless.

Would you care to elaborate exactly what the base class cell_entry_base
does (you noted: // whatever you need to know to locate a cell). I'd
also be grateful if you add a little more flesh (or at least comments to
the template specializations for class cell_entry). It is likely that I
may have to come back to you several times during my implementation - I
hope you don't mind :) (please indicate if you are too busy to assist
- though, in which case I'll keep it simple and use my less elegant
method - but I really like this more compact approach...)

I am glad I have been a littel helpful.

The class cell_entry_base is designed to consist any data or operation that
is necessary to locate a cell in your database. This is highly
implementation dependent--how it is implemented is directly related to the
database you are using. In situations where multi-connection, multi-table
database are concerned, you probably have to elaborate the class even a
little further.

That said, if your database can always use an int-int pair to locate a cell
directly, cell_entry_base is quite triviall:

class cell_entry_base
{
public:
int col;
int row;

// ...
};


Regards,
Ben
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top