Challenge: Can we implement Product Type access (P0327R0) using the reflection interface?

186 views
Skip to first unread message

Vicente J. Botet Escriba

unread,
Mar 9, 2017, 2:27:32 AM3/9/17
to refle...@isocpp.org

Hi,

The intention of my P0327R0 proposal is to define an Product-type access interface (that is a clone of the tuple-like access interface) *independently* of whether it is provided by some intrinsic or by reflection (I left this as an implementation detail as I don't know if it is possible or not).

There was a request from the Kona C++ meeting to see if and how we can implement the product type access (P0327R0) using the reflection interface. I believe that the structure binding wording is quite complex and I have not taken too much time (in reality no time at all) to see how to implement it using reflection.

So here it is the challenge I propose to all of you: Can we implement the P0327R0 product type access interface (or something similar) with the reflection interface? If yes, how? If not, what could be missing? or what could help to make it easier?

Any help would be really appreciated :)


Best,
Vicente

P.S. I've sent a message to LEWG to check if the proposed interface is the one to have.


Jackie Kay

unread,
Mar 9, 2017, 3:34:01 PM3/9/17
to refle...@isocpp.org
First of all, I think this is a very important consideration since static reflection essentially turns all structs and classes into product types that could be accessible with your proposed interface.

My question about the implementation of product-type access is how product types indicate which of their members are "type" fields which are accessible by the interface, and which members are just boilerplate/internal storage.

With static reflection we can very easily implement product type access for structs/classes.

However, for other "container" product types, they would need to provide a way of mapping from their internal storage to a unified interface that can be understood by the generic product type functions, either providing a specialization of the product type functions or a unified interface that the generic product type functions could access (think of a "ProductType concept"). For std::tuple this is already implemented, but for future product types (compile-time maps?) this is an important consideration. Reflection might make this easier because you could reflect on the internal storage, but reflecting on the member fields of the tuple class without indicating which ones are relevant to the product type interface would not work.

Under the assumption that all structs/classes are product types under this interface you could say something like "product type access only provides access for the public members of a struct". But you would still need some kind of interface for "container" types since their internal storage is probably private, or even contained in a separate implementation struct--regardless, it's an implementation detail.

I'm not sure how to deal with bitfields as I haven't thought much about it, and I don't even know off the top of my head how they fit into the current reflection proposals.

Hope you found this helpful,

Jackie

--
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.

Jackie Kay

unread,
Mar 20, 2017, 7:40:37 PM3/20/17
to refle...@isocpp.org
Vicente,

I made a prototype of this a few days ago with Matus' "reflexpr" fork of Clang. It's quite concise. Does this look like a correct implementation of your interface?

https://gist.github.com/jacquelinekay/6bcacee7a3bce7d82b9d6387b6afee96

Jackie

Botet Escriba Vicente J.

unread,
May 4, 2017, 7:00:52 PM5/4/17
to SG 7 - Reflection
Hi, raaly sorry for the late response. I don't survey this ML very often.


Le jeudi 9 mars 2017 21:34:01 UTC+1, Jackie Kay a écrit :
First of all, I think this is a very important consideration since static reflection essentially turns all structs and classes into product types that could be accessible with your proposed interface.

My question about the implementation of product-type access is how product types indicate which of their members are "type" fields which are accessible by the interface, and which members are just boilerplate/internal storage.

Product type follows the same rules as structured binding. There is no possibility for boilerplate/internal storage. 

With static reflection we can very easily implement product type access for structs/classes.

However, for other "container" product types, they would need to provide a way of mapping from their internal storage to a unified interface that can be understood by the generic product type functions, either providing a specialization of the product type functions or a unified interface that the generic product type functions could access (think of a "ProductType concept"). For std::tuple this is already implemented, but for future product types (compile-time maps?) this is an important consideration. Reflection might make this easier because you could reflect on the internal storage, but reflecting on the member fields of the tuple class without indicating which ones are relevant to the product type interface would not work.

Under the assumption that all structs/classes are product types under this interface you could say something like "product type access only provides access for the public members of a struct". But you would still need some kind of interface for "container" types since their internal storage is probably private, or even contained in a separate implementation struct--regardless, it's an implementation detail.

No this is not the definition of the ProductType I defined in P0327R1. Have you read it? Any feedback is welcome?
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0327r1.pdf

I'm not sure how to deal with bitfields as I haven't thought much about it, and I don't even know off the top of my head how they fit into the current reflection proposals.

bitfields are out of scope for the time being, as we can not get a reference to them.
 

Hope you found this helpful,


yes, thanks a lot,
Vicente

Botet Escriba Vicente J.

unread,
May 4, 2017, 7:14:38 PM5/4/17
to SG 7 - Reflection


Le mardi 21 mars 2017 00:40:37 UTC+1, Jackie Kay a écrit :
Vicente,

I made a prototype of this a few days ago with Matus' "reflexpr" fork of Clang. It's quite concise. Does this look like a correct implementation of your interface?

https://gist.github.com/jacquelinekay/6bcacee7a3bce7d82b9d6387b6afee96


Thanks Jackie.

The definition of Product Type in P0327R1 is

## Product types terms

If `E` is an array type with element type `T`,

* the *product type size of E* is equal to the number of elements of E,
* the *product type i <sup>th</sup>-element of E* is `e[i-1]`,
* the *product type i <sup>th</sup>-element type of E* is `T`.
 
[ Note: The top-level cv-qualifiers of T are cv. — end note ]

Otherwise, if the expression `std::tuple_size<E>::value` is a well-formed integral constant expression,

* the *product type size of E* is equal equal to `std::tuple_size<E>::value`,

If the expression `std::tuple_element<E>::type` is a well-formed type
* the *product type i <sup>th</sup>-element type of E* is this type

The unqualified-id `get` is looked up in the scope of `E` by class member access lookup (3.4.5), and if that finds at least one declaration, the initializer is `e.get<i - 1>()`. Otherwise, the initializer is `get<i - 1>(e)`, where get is looked up in the associated namespaces (3.4.2). In either case, `get<i - 1>` is interpreted as a template-id. [ Note: Ordinary unqualified lookup (3.4.1) is not performed. — end note ]

* the *product type i <sup>th</sup>-element of E* is this initializer


Otherwise, all of `E`’s non-static data members shall be public direct members of `E` or of the same unambiguous public base class of `E`, `E` shall not have an anonymous union member. The `i`th non-static data member of `E` in declaration order is designated by `mi`.

* the *product type size of E* is equal equal to the number of non-static data members of E.
* the *product type i <sup>th</sup>-element of E* is this `e.mi`,
* the *product type i <sup>th</sup>-element type of E* is the declared type of that `E::mi`.
 
Otherwise the terms are undefined.

If any of the previous terms is not defined the other are not defined.


Your prototype takes in account the last case "Otherwise, all of `E`’s non-static data members shall be public direct members of `E`". However I believe it doesn't takes in account the part or of the same unambiguous public base class of `E`.

I think the hard part is
"The unqualified-id `get` is looked up in the scope of `E` by class member access lookup (3.4.5), and if that finds at least one declaration, the initializer is `e.get<i - 1>()`. Otherwise, the initializer is `get<i - 1>(e)`, where get is looked up in the associated namespaces (3.4.2). In either case, `get<i - 1>` is interpreted as a template-id. [ Note: Ordinary unqualified lookup (3.4.1) is not performed. — end note ] "

Thanks for the help,
Vicente


Reply all
Reply to author
Forward
0 new messages