Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

having the same method but with a different argument data type

23 views
Skip to first unread message

Lynn McGuire

unread,
Jun 16, 2020, 2:40:41 PM6/16/20
to
Hi,

Is there a way to have the same method but with a different argument
data type for a single argument ? For instance, the following methods
that I have greatly simplified:

class DataItem : public ObjPtr
{
int aAvalueInt;
double aValueDouble;
std::vector <int> aValueIntArray;
std::vector <std::string> aValueStringArray;
}

ObjPtr * DataItem::store(int aValue)
{
// do some stuff
aValueInt = aValue;
// do some stuff
return this;
}

ObjPtr * DataItem::store (double aValue)
{
// do some stuff
aValueDouble = aValue;
// do some stuff
return this;
}

ObjPtr * DataItem::store (std::vector <int> aValue)
{
// do some stuff
aValueIntArray = aValue;
// do some stuff
return this;
}

ObjPtr * DataItem::store (std::vector <std::string> aValue)
{
// do some stuff
aValueStringArray = aValue;
// do some stuff
return this;
}

Is there some way to combine all of these methods (and the other data
types) into a single method ?

Thanks !

Lynn

Bonita Montero

unread,
Jun 16, 2020, 2:51:05 PM6/16/20
to
> Is there some way to combine all of these methods
> (and the other data types) into a single method ?

Try std::variant<...>.
But that's less performant.

Bonita Montero

unread,
Jun 16, 2020, 3:03:03 PM6/16/20
to
How about this:

#include <variant>
#include <vector>
#include <string>

using namespace std;

struct DataItem
{
int aAvalueInt;
double aValueDouble;
vector<int> aValueIntArray;
vector<string> aValueStringArray;
};

using var_t = variant<int, double, vector<int>, vector<string>>;

void f( var_t &var, DataItem &di )
{
enum
{
INT,
DOUBLE,
VEC_INT,
VEC_STR
};
switch( var.index() )
{
case INT:
di.aAvalueInt = get<INT>( var );
break;
case DOUBLE:
di.aValueDouble = get<DOUBLE>( var );
break;
case VEC_INT:
di.aValueIntArray = get<VEC_INT>( var );
break;
case VEC_STR:
di.aValueStringArray = get<VEC_STR>( var );
break;
}
}

Compile it with C++17 enabled.

Bonita Montero

unread,
Jun 16, 2020, 3:21:26 PM6/16/20
to
This more exactly maps to what you want:

#include <variant>
#include <vector>
#include <string>

using namespace std;

struct ObjPtr
{
// ...
};

struct DataItem : public ObjPtr
{
enum
{
INT,
DOUBLE,
VEC_INT,
VEC_STR
};
using var_t = variant<int, double, vector<int>, vector<string>>;
ObjPtr *store( var_t &var );

int aAvalueInt;
double aValueDouble;
vector<int> aValueIntArray;
vector<string> aValueStringArray;
};


ObjPtr *DataItem::store( var_t &var )
{
switch( var.index() )
{
case INT:
aAvalueInt = get<INT>( var );
break;
case DOUBLE:
aValueDouble = get<DOUBLE>( var );
break;
case VEC_INT:
aValueIntArray = get<VEC_INT>( var );
break;
case VEC_STR:
aValueStringArray = get<VEC_STR>( var );
break;
}
return this;
}

Alf P. Steinbach

unread,
Jun 16, 2020, 4:18:42 PM6/16/20
to
When you discriminate only on type, as in the above example code, you
can only have one member of each type.

If that restriction is OK with you then just make `store` a function
template:

template< class Arg >
auto store( Arg arg ) -> ObjPtr*

In the function body there are two main ways to select the member to
assign to, i.e. ways to specify the type -> member association. Maybe
there are other techniques too. But only two popped up in my brain now.

One way is to have a function overloaded for each relevant member type:

auto DataItem::member( int& ) -> int& { return aValueInt; }
auto DataItem::member( double& ) -> double& { return aValueDouble; }
// etc., then

template< class Arg >
auto DataItem::store( Arg arg )
-> ObjPtr*
{
// Do some stuff.
member( arg ) = move( arg );
// Do some more stuff.
return this;
}

Another way is to let the data members be base class sub-objects of
DataItem. Then they can be selected by `static_cast` to the relevant
type. Since one cannot derive from `int` or `double` it's necessary to
use some kind of boxing class, e.g.

template< class Value >
struct Boxed_
{
Value value;
};

class DataItem:
public ObjPtr,
private Boxed_<int>,
private Boxed_<double>,
// etc.
{
template< class Arg >
auto member( int& )
-> Arg&
{ return static_cast<Boxed_<Arg>&>( *this ).value; }

// + The `store` function template as before.
};

It's possible though that these techniques, while addressing directly
what you're asking for, don't address the Real Issue. Because inheriting
from an `ObjPtr` class, and returning a raw pointer from a `store`
method, indicate a struggling, unnatural design. So likely this is an
X/Y problem where you have a Real Issue X, you imagine that Y could be a
good solution to X, you can't make Y work cleanly, and you ask about Y?

- Alf

Lynn McGuire

unread,
Jun 17, 2020, 2:53:11 PM6/17/20
to
Thanks, I need to review and think about this. There are actually over
ten base data types in my software.

Lynn



Lynn McGuire

unread,
Jun 17, 2020, 2:57:12 PM6/17/20
to
This is code that I have had in our product since 2003 that I am
revising at the moment and disturbed by our duplicated code in each of
the 10+ methods.

This code was actually written in Smalltalk back in 1990 or so. Two of
my programmers and I converted it to C++ in 2002-3 when we rebuilt the
product totally in Win32 C++. ObjPtr is our base class that mimics the
base object class in Smalltalk. Works very well for us in 450,000+
lines of C++ code.

I had not though about using a template. I had a bad experience with a
template a couple of decades ago in the Visual C++ compiler and stay
away from them now.

Thanks,
Lynn

Jorgen Grahn

unread,
Jun 17, 2020, 5:05:50 PM6/17/20
to
On Wed, 2020-06-17, Lynn McGuire wrote:
...
> I had not though about using a template. I had a bad experience with a
> template a couple of decades ago in the Visual C++ compiler and stay
> away from them now.

I can happily recommend templates; they are good for all kinds of tasks
in all kinds of programs.

I wish it was easier to learn how to apply them, though. For me it's
still trial and error: I can "smell" an opportunity to simplify code
with use of templates, but not know exactly how to proceed. Then
after some failed attempts, I may end up with a really clean solution.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
0 new messages