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

How to overload get<>() ?

48 views
Skip to first unread message

bol...@nowhere.org

unread,
Jan 9, 2020, 4:38:04 AM1/9/20
to
Morning

Is there a way to overload get so that when used on a user defined class it
will return values defined by the user , not simple an index value? Or to
put it another way, what do standard classes like tuple have to implement
in order for get<>() to work with them?

eg:

struct myclass
{
blah b;
int i;
string s;
:
:
};


cout << get<0>(obj); <- How would I make this return string s for example?

Öö Tiib

unread,
Jan 9, 2020, 3:42:35 PM1/9/20
to
The std::tuple is variadic template and so its elements are
enumerated during its generation. For such stinky myclass it
is most trivial to make those manually.

Random attempt of mine for example:

#include <iostream> // for cout and endl

using blah = double; // to make stinky myclass to compile
using string = void*; // to make stinky myclass to compile

struct myclass
{
blah b;
int i;
string s;
// : <- stinky syntax error commented out
// : <- same here
template<int> auto get();
};

template<>
auto myclass::get<0>() {return b;}
template<>
auto myclass::get<1>() {return i;}
template<>
auto myclass::get<2>() {return s;}

int main()
{
myclass m {42.42, 42, nullptr};
std::cout << m.get<0>() << " "
<< m.get<1>() << " "
<< m.get<2>() << std::endl;
}

Seems to work on online compiler.
<http://coliru.stacked-crooked.com/a/bab622316924d788>



bol...@nowhere.org

unread,
Jan 10, 2020, 7:18:47 AM1/10/20
to
On Thu, 9 Jan 2020 12:42:23 -0800 (PST)
=?UTF-8?B?w5bDtiBUaWli?= <oot...@hot.ee> wrote:
>On Thursday, 9 January 2020 11:38:04 UTC+2, bol...@nowhere.org wrote:
>> Morning
>>
>> Is there a way to overload get so that when used on a user defined class it
>> will return values defined by the user , not simple an index value? Or to
>> put it another way, what do standard classes like tuple have to implement
>> in order for get<>() to work with them?
>>
>> eg:
>>
>> struct myclass
>> {
>> blah b;
>> int i;
>> string s;
>> :
>> :
>> };
>>
>>
>> cout << get<0>(obj); <- How would I make this return string s for example?
>
>The std::tuple is variadic template and so its elements are
>enumerated during its generation. For such stinky myclass it
>is most trivial to make those manually.

If quite capable of writing a class method called get() though I wouldn't use
such a ridiculously complex method that you have, I wanted to how to use
the standard library get() for my classes as per tuple and variant. It can be
done with a tuple cast overload method in the class but unfortunately when
using get() it requires an explicit cast in the call. eg:

auto val = get<0>((tuple<string,int,int>)(myobj));

Which works but is ugly.

guinne...@gmail.com

unread,
Jan 10, 2020, 10:04:44 AM1/10/20
to
I have presumed (as Öö Tiib also did) that you actually want the mapping

get<0>(obj) <=> obj.b
get<1>(obj) <=> obj.i
get<2>(obj) <=> obj.s

The following function templates did the trick for me. The second one also
facilitates lvalue access (just as the std::get<>() function templates do),
so you can perform indexed-member assignments, e.g.

get<2>(obj) = "foo";

---- 8< ----

#include <tuple>

template<std::size_t I> constexpr auto const& get(myclass const& obj)
{ return std::get<I>(std::tie(obj.b, obj.i, obj.s)); }

template<std::size_t I> constexpr auto& get(myclass& obj)
{ return std::get<I>(std::tie(obj.b, obj.i, obj.s)); }

Öö Tiib

unread,
Jan 13, 2020, 4:17:04 AM1/13/20
to
On Friday, 10 January 2020 14:18:47 UTC+2, bol...@nowhere.org wrote:
> On Thu, 9 Jan 2020 12:42:23 -0800 (PST)
> Öö Tiib <oot...@hot.ee> wrote:
> >On Thursday, 9 January 2020 11:38:04 UTC+2, bol...@nowhere.org wrote:
> >> Morning
> >>
> >> Is there a way to overload get so that when used on a user defined class it
> >> will return values defined by the user , not simple an index value? Or to
> >> put it another way, what do standard classes like tuple have to implement
> >> in order for get<>() to work with them?
> >>
> >> eg:
> >>
> >> struct myclass
> >> {
> >> blah b;
> >> int i;
> >> string s;
> >> :
> >> :
> >> };
> >>
> >>
> >> cout << get<0>(obj); <- How would I make this return string s for example?
> >
> >The std::tuple is variadic template and so its elements are
> >enumerated during its generation. For such stinky myclass it
> >is most trivial to make those manually.
>
> If quite capable of writing a class method called get() though I wouldn't use
> such a ridiculously complex method that you have, I wanted to how to use
> the standard library get() for my classes as per tuple and variant.

It wasn't clear from you OP what you are capable of (if anything).
There is only small semantic difference if something is
implemented to use syntax "a.foo(b)" or "foo(a,b)". I prefer
"a.foo(b)" when the parameter "a" is a reference of existing
object.

> It can be
> done with a tuple cast overload method in the class but unfortunately when
> using get() it requires an explicit cast in the call. eg:
>
> auto val = get<0>((tuple<string,int,int>)(myobj));
>
> Which works but is ugly.

In sense of standard your C-style cast (that is effectively
reinterpret_cast and is warned about by lot of tools) is not
"ridiculously simpler". The std::tuple is not required to be of
standard layout. The std::string (I suspect one of members
of your myclass is supposed to be std::string) is not standard
layout and so neither that tuple nor your myclass is standard
layout. So reinterpret_cast there is undefined behavior.
Even if some compiler provides extensions (can you cite what
compiler and where?) it is non-portable.

The "std::get" is not a customization point for the standard
library. The overloads (for pair, tuple and array) do not allow for
user-defined overloads explicitly. So adding a declaration of
your own "get" overload into namespace "std" is undefined
behaviour.

You can add non-member "get" into same namespace as
your "myclass" is. Then ADL will make it to work for "get" like
it already works on case of std::pair, std::tuple or std::array.
But do not use reinterpret_cast. Do like I suggested or tie
like other poster suggested.

0 new messages