Anyone working on implementing idreflexpr?

225 views
Skip to first unread message

Roland Bock

unread,
Jan 4, 2017, 1:44:44 PM1/4/17
to SG 7 - Reflection
Hi,

As much as I am fascinated by P0194R2 and its experimental implementation https://github.com/matus-chochlik/clang/tree/reflexpr, reflection will become really interesting only when I can take the names I found in the analysis and use them for creating new types.

P0385R1 proposes an operator idreflexpr(const char (&)[N]) in section 6.4 that could be used like this:

template <typename M>
struct X
{
   std
::size_t idreflexpr(meta::get_base_name_v<M>);  //< This would be awesome!
};

struct bar
{
   
int foo;
};
using meta_bar_foo = reflexpr(bar::foo);

using XFoo = X<meta_bar_foo>;

XFoo would then be something like this

struct XFoo
{
   std
::size_t foo;
};

There are also several motivating examples in P0385R1.

Question:
Is anyone already working on implementing such a feature in clang already?

If not, can anybody give me some pointers where to start? I read some clang source code yesterday and was positively surprised by the readability, but still, it would help to get a few hints :-)
The example above would be wonderful. I don't need idreflexpr to work in all places. But in order to be useful it needs to work for names of data members of template structs/classes, where the name depends on a template argument.

I guess I'd have to come up with a temporary name (or placeholder?) when initially parsing the template and then fill in the "final" name once the template gets specialized.

Any hints/suggestions appreciated.

Thanks,

Roland

Klaim - Joël Lamotte

unread,
Jan 5, 2017, 6:03:10 AM1/5/17
to refle...@isocpp.org
I am interested to test it too.
(I will be trying the current implementation starting today BTW)

Joël Lamotte


--
You received this message because you are subscribed to the Google Groups "SG 7 - Reflection" group.
To unsubscribe from this group and stop receiving emails from it, send an email to reflection+unsubscribe@isocpp.org.
To post to this group, send email to refle...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/reflection/.
For more options, visit https://groups.google.com/a/isocpp.org/d/optout.

Matus Chochlik

unread,
Jan 5, 2017, 10:57:21 AM1/5/17
to refle...@isocpp.org
Hi Roland,

I'll try to get a simplified version of idreflexpr going over the weekend, but no big promises yet.

--Matus

Roland Bock

unread,
Jan 5, 2017, 11:04:45 AM1/5/17
to refle...@isocpp.org
Hi Matus,

Awesome!

I am also looking into it, but this is my first attempt ever to change
anything in clang, so it will probably take a bit longer...

Cheers,

Roland

On 2017-01-05 16:57, Matus Chochlik wrote:
> Hi Roland,
>
> I'll try to get a simplified version of idreflexpr going over the
> weekend, but no big promises yet.
>
> On Wed, Jan 4, 2017 at 7:44 PM, Roland Bock <rb...@eudoxos.de
> <mailto:rb...@eudoxos.de>> wrote:
>
> Hi,
>
> As much as I am fascinated by P0194R2 and its experimental
> implementation https://github.com/matus-chochlik/clang/tree/reflexpr
> <https://github.com/matus-chochlik/clang/tree/reflexpr>, reflection
> will become really interesting only when I can take the names I
> found in the analysis and use them for creating new types.
>
> P0385R1 proposes an operator idreflexpr(const char (&)[N]) in
> section 6.4 that could be used like this:
>
> |
> template<typenameM>
> structX
> {
> std::size_t idreflexpr(meta::get_base_name_v<M>); //< This would
> be awesome!
> };
>
> structbar
> {
> intfoo;
> };
> usingmeta_bar_foo =reflexpr(bar::foo);
>
> usingXFoo=X<meta_bar_foo>;
> |
>
> XFoo would then be something like this
>
> |
> structXFoo
> {
> std::size_t foo;
> };
> |
>
> There are also several motivating examples in P0385R1.
>
> Question:
> Is anyone already working on implementing such a feature in clang
> already?
>
> If not, can anybody give me some pointers where to start? I read
> some clang source code yesterday and was positively surprised by the
> readability, but still, it would help to get a few hints :-)
> The example above would be wonderful. I don't need idreflexpr to
> work in all places. But in order to be useful it needs to work for
> names of data members of template structs/classes, where the name
> depends on a template argument.
>
> I guess I'd have to come up with a temporary name (or placeholder?)
> when initially parsing the template and then fill in the "final"
> name once the template gets specialized.
>
> Any hints/suggestions appreciated.
>
>
> --Matus
>
> --
> You received this message because you are subscribed to the Google
> Groups "SG 7 - Reflection" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to reflection+...@isocpp.org
> <mailto:reflection+...@isocpp.org>.
> To post to this group, send email to refle...@isocpp.org
> <mailto:refle...@isocpp.org>.

Thiago Macieira

unread,
Jan 5, 2017, 12:47:47 PM1/5/17
to refle...@isocpp.org
Em quarta-feira, 4 de janeiro de 2017, às 10:44:43 PST, Roland Bock escreveu:
> Hi,
>
> As much as I am fascinated by P0194R2 and its experimental
> implementation https://github.com/matus-chochlik/clang/tree/reflexpr,
> reflection will become really interesting only when I can take the names I
> found in the analysis and use them for creating new types.

I'm not trying to be dismissive: why do you want this?

Can you give a conctrete use-case of creating new types whose member names
match existing type names or their member names?

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Mathias Gaunard

unread,
Jan 5, 2017, 12:52:02 PM1/5/17
to refle...@isocpp.org
Say you're creating a wrapper that must satisfy the same interface as the underlying type, you iterate its members then re-create them through that keyword.
Of course you'll need to use recursive inheritance to achieve this, unless we somehow extend TPP to be used for declarations.

--
You received this message because you are subscribed to the Google Groups "SG 7 - Reflection" group.
To unsubscribe from this group and stop receiving emails from it, send an email to reflection+unsubscribe@isocpp.org.
To post to this group, send email to refle...@isocpp.org.

Matus Chochlik

unread,
Jan 5, 2017, 12:55:58 PM1/5/17
to refle...@isocpp.org
On Thu, Jan 5, 2017 at 6:51 PM, Mathias Gaunard <mat...@gaunard.com> wrote:
Say you're creating a wrapper that must satisfy the same interface as the underlying type, you iterate its members then re-create them through that keyword.

Right, for example in a ORM library.
 
Of course you'll need to use recursive inheritance to achieve this, unless we somehow extend TPP to be used for declarations.

Actually there is a long-term plan to add such functionality, so you'd be able to do, things like:

template <meta::Named ... MN>
struct my_struct
{
  make_type_t<MN> idreflexpr(MN)...;
};

Klaim - Joël Lamotte

unread,
Jan 5, 2017, 12:56:12 PM1/5/17
to refle...@isocpp.org
Indeed. One typical example is a Structure Of Array type generated based on a type definition.




Peter Bindels

unread,
Jan 5, 2017, 12:57:38 PM1/5/17
to refle...@isocpp.org
What about the same, but for virtual functions?

Matus Chochlik

unread,
Jan 5, 2017, 1:10:47 PM1/5/17
to refle...@isocpp.org
On Thu, Jan 5, 2017 at 6:57 PM, Peter Bindels <dasc...@gmail.com> wrote:
What about the same, but for virtual functions?

I don't see why not. The plan is, that you should be able to use `idreflexpr(...)` basically everywhere where you can use a regular identifier. There is some discussion about this in P0385R1 (section 6.4, p.60).

Roland Bock

unread,
Jan 5, 2017, 2:18:47 PM1/5/17
to SG 7 - Reflection


On Thursday, January 5, 2017 at 6:47:47 PM UTC+1, Thiago Macieira wrote:
Em quarta-feira, 4 de janeiro de 2017, às 10:44:43 PST, Roland Bock escreveu:
> Hi,
>
> As much as I am fascinated by P0194R2 and its experimental
> implementation https://github.com/matus-chochlik/clang/tree/reflexpr,
> reflection will become really interesting only when I can take the names I
> found in the analysis and use them for creating new types.

I'm not trying to be dismissive: why do you want this?

Can you give a conctrete use-case of creating new types whose member names
match existing type names or their member names?


Note that idreflexpr takes a compile time string, it does not necessarily have to be taken from a reflection meta object. The examples below use both, names from meta objects and names from other compile time strings.

*) sqlpp11:
In this EDSL for SQL in C++, tables are represented by types that have one or more data members representing the columns.

You can then create SQL and evaluate statements like this:

for (const auto& row : db(select(tab.id, tab.first_name, tab.last_name)
                         
.from(tab)
                         
.where(tab.dob > 1920)))
{
   foo
(row.id, row.first_name, row.last_name);
}

The type of row is constructed by the library depending of the selected columns. This works today. So why bother? Because it is annoying to code. For each name, there has to be a separate template that happens to have a member of that name and can then be used as a base class. It involves code generators, macros, or someone who likes repetitive typing a lot.

As mentioned by Matus, the long term goal is to have something like this:

template <meta::Named ... MN>
struct my_struct
{
  make_type_t
<MN> idreflexpr(MN)...;
};

Then neither tables not rows would require any inheritance any more. In the case of tables, it currently is variadic CRTP. The name would just be template parameter for the column or result field types.

Assuming that compile time strings could be created from string literals, we could also have

for (const auto& row : db(select(tabFoo.id.as<"left"_ct>(),
                                 tabBar
.id.as<"right"_ct>())
                         
.from(tabFoo.join(tabBar).on(tabFoo.name == tabBar.name))
                         
.where(tabFoo.id < 1000)))
{
   doSomething
(row.left, row.right);
}


As of now, such names as left and right need to be template classes again, generated by a PP macro outside of the current function (aka far away).


*) sqlpp11 for containers:
Eric Niebler once said that he would like to see SQL for containers or streams, too. Well, actually I have a prototype for that, but if I want to run SQL on say a vector<Foo>, then I need create a class that acts as a table definition with columns that represent the data members of Foo. As of today I see no other way than to use a code generator. That is a lot of overhead. Nobody would use that.

With the current reflection plus idreflexpr I could generate those table-classes with a little bit of generic meta programming directly from Foo. Suddenly, this is no hassle at all for the library user.

I would probably use that every now and then. Sometimes SQL expressions might be simpler to read and write than STL algorithms with a bunch of lambdas.


*) Named tuple data members:
Say you want to return several values from a function. Tuple or hand-coded struct? 
  • Tuples are so much easier for the author of the function. But they are ugly for users who want to access certain values.
  • Hand-written structs might need additional comparison operators. And they aren't well suited for generic programming sometimes.
So how about we had a tuple, whose data members were defined by type AND name? You wouldn't have to choose any more. You could access data members by name like in a "normal" struct or by index as in today's tuple.


Cheers,

Roland

Matus Chochlik

unread,
Jan 7, 2017, 4:12:51 PM1/7/17
to refle...@isocpp.org
Hi,

On Wed, Jan 4, 2017 at 7:44 PM, Roland Bock <rb...@eudoxos.de> wrote:
[8<]
Question:
Is anyone already working on implementing such a feature in clang already?

If not, can anybody give me some pointers where to start? I read some clang source code yesterday and was positively surprised by the readability, but still, it would help to get a few hints :-)
The example above would be wonderful. I don't need idreflexpr to work in all places. But in order to be useful it needs to work for names of data members of template structs/classes, where the name depends on a template argument.

So I've been playing with this a little today. It turns out that implementing `idreflexpr` is fairly trivial outside of templates, but the techniques seem pretty useless *inside* templates. Maybe doing an annotation when parsing the `idreflexpr` operator and using `Token::setAnnotationValue` could help, but I didn't find out yet how that interacts with template instantiation.

I guess I'd have to come up with a temporary name (or placeholder?) when initially parsing the template and then fill in the "final" name once the template gets specialized.

I've also been looking at `clang::IdentifierInfo` but I can't get it to work with the AST transforms yet. Other approach might be to fix all the descendants of `Decl`, like `FieldDecl` where we want to support `idreflexpr`, but there are quite a few of them so this approach might not scale very well.
 

Any hints/suggestions appreciated.
 
Same here ;) If any clang people hang out around here; tips are welcome.

Anyway I'll have a second look at this tomorrow.

--Matus
Reply all
Reply to author
Forward
0 new messages