Comments/Questions on P0194R2/P0385R1

113 views
Skip to first unread message

Roland Bock

unread,
Jan 2, 2017, 12:56:09 PM1/2/17
to SG 7 - Reflection
Hi there,

In the past few days I finally found the time to play with the experimental reflection implementation in clang by Matus Chochlik (https://github.com/matus-chochlik/clang/tree/reflexpr). Very impressive!

Thanks to Matus Chochlık, Axel Naumann, David Sankel for the proposals and the experimental implementation. It is fun playing with it. If you haven't tried to experiment with it, I strongly suggest you do. This gives you the chance to get a feel for what the current proposal (P0194R2) really has to offer.

While doing so, I ran into the occasional bug (it is experimental, so this is to be expected), and wrote down a couple of coments/questions regarding the proposal (P0194R2) and its rationale (P0385R1). Bugs are reported on github, comments and questions follow below:


*) Metaobjects are types:
Not being a language lawyer at all, I would still argue that the wording is sub-optimal. In other contexts, objects have a type. These metaobjects are types? In particular, a metaobject can be the type of an object, since you can construct an object of a metaobject. That just seems confusing to me.

Maybe we should call them meta types instead?

However, to be consistent with the proposal, I will continue to call them metaobjects below.

*) Metaobjects are "opaque":
Earlier revisions of the proposal did not allow the creation of metaobject objects. Maybe then it made sense to just not say anything concrete about the metaobjects. 

However, now that we can construct them, we should say a bit more, I guess. For instance, it seemed like the most natural thing for me to create constexpr objects of metaobjects. The current proposal does not say whether that is legal.

IMO, the easiest way to go about it would be to say that metaobjects are empty structs. They have all the traits we need and we don't have to specify their behavior (other than in our concepts and traits). And the mystical opaqueness would just vanish.

*) Namespace for metaobjects:
The proposal does not say anything about the namespace of metaobjects, but it would be helpful to know for ADL, for instance.

But since metaobjects are types, they can be reflected (so much for opaqueness, btw). So we can take a look at where they live in the experimental implementation: They reside in namespace std.

I believe that the proposal should specify the namespace for metaobjects and I believe that should be std::meta. For instance, we could then add constexpr functions in parallel to all the current traits (e.g. constexpr auto get_aliased_f(const T&) { return get_aliased_m<T>{}; }) that would work well with ADL.

*) Reflecting (record) variables:
I understand from the examples in P0385R1 one of the main motivations for reflecting variables is obtaining their name. Also, I can 

  •  learn if the variable is static
  •  obtain a pointer (or class data member pointer) to it.

And I have the well known traits to know whether it is const or volatile.

Missing traits are IMO:

  •   is_constexpr
  •   is_inline
  •   has_default_value (in case of class members)

*) Namespaces:
Consider this program

#include <reflexpr>
#include <iostream>
#include <vector>
namespace foo
{
 
class bar{};
 
using V = std::vector<bar>;
}


int main()
{
  std
::cout << std::meta::get_display_name_v<std::meta::get_scope_m<reflexpr(V)>> << std::endl;
  std
::cout << std::meta::get_display_name_v<std::meta::get_scope_m<reflexpr(std::vector<foo::bar>)>> << std::endl;
}

It prints:

foo
std
::__1

`V`'s scope is `foo`, which seems obvious. `V`'s namespace is `std::__1`. This is also fine, because vector is actually declared inside the inline namespace `__` inside namespace std in libc++. Still, it is a bit surprising.

Again, it would be nice to have an `is_inline` trait to check whether a namespace is inline. That way I could choose to omit the `::__1` when printing the name, for instance.

It might also be interesting to obtain associated namespaces. This might be useful for diagnostic purposes when trying to understand ADL for complex types/functions. See also next item.

*) Template specializations:
Is there a way to obtain the arguments of a template specialization? For instance, 

using T = std::vector<int>


using MV = get_aliased_m<reflexpr(T)>;


Is there a way to learn that `MV` represents a template specialization of `std::vector` (or `std::__1::vector`) with `int` being the argument for the first template parameter, while the other parameters take their default arguments?

How can I compose the "display name" from the base names otherwise?

*) Alias or the real thing?
Consider this code:

#include <reflexpr>
#include <iostream>


template<typename T>
auto foo(const T& t)
{
  std
::cout << std::meta::get_base_name_v<reflexpr(T)> << std::endl;
}


int main()
{
  foo
(42);
}


This program prints `T`. I won't say that that is wrong, but I can say that it took me by surprise. I was expecting to see `int` (probably because I read that part of the proposal only afterwards).

Personally, I would prefer if the meta object yielded by `reflexpr(T)` represented `int` in this case and there were a meta function `template <typename T> struct get_alias<T>;` that provides a meta object representing the `T`.

I claim that `get_alias` to get the alias (e.g. `T`) would also be more intuitive than `get_aliased` to get the underlying type (e.g. `int`).

*) Suffix `_m`:
I find the suffix `_m` confusing rather than helpful. Those metafunctions return types. They are implemented as `template<typename T> using xxx_m = typename xxx<T>::type;`.

Why not use the canonical suffix `_t`? I understand it was like this before. I do not understand why it was changed to `_m`. Does not make much sense to me. Sure, they might be those special opaque meta types (see my first items), but they are still types.

*) get_base_classes/get_base_class/get_base_name:

  • get_base_classes takes a meta Class and returns a meta Sequence of meta Inheritances
    • it does not yield base classes, but inheritances
  • get_base_class takes a meta Inheritance and returns a meta Class
    • it does not yield a base class of an inheritance (no such thing)
  • get_base_name has nothing to do with inheritance at all, yet the current naming scheme seems to imply that.

Suggested renaming:
    s/get_base_classes/get_inheritances/
    s/get_base_class/get_class/

*) is_class/is_struct:
I wonder if this distinction is really useful. The only difference between struct and class is the default accessibility of members and base classes, isn't it? And we can obtain the access specifiers of each member. So what's the point?

They are so interchangeable that a specialization of a template struct can be a class and vice versa.

Also, there is a concept meta::Class but not meta::Struct.


So much for the moment. Thanks for reading :-)

Cheers,

Roland

Matus Chochlik

unread,
Jan 2, 2017, 3:26:09 PM1/2/17
to refle...@isocpp.org
Hi Roland,

On Mon, Jan 2, 2017 at 6:56 PM, Roland Bock <rb...@eudoxos.de> wrote:

In the past few days I finally found the time to play with the experimental reflection implementation in clang by Matus Chochlik (https://github.com/matus-chochlik/clang/tree/reflexpr). Very impressive!

Thanks to Matus Chochlık, Axel Naumann, David Sankel for the proposals and the experimental implementation. It is fun playing with it. If you haven't tried to experiment with it, I strongly suggest you do. This gives you the chance to get a feel for what the current proposal (P0194R2) really has to offer.

Thank you for your kind words! I only wish I had more free time/willpower to improve the specification and implementation :)
 

While doing so, I ran into the occasional bug (it is experimental, so this is to be expected), and wrote down a couple of coments/questions regarding the proposal (P0194R2) and its rationale (P0385R1). Bugs are reported on github, comments and questions follow below:


*) Metaobjects are types:
Not being a language lawyer at all, I would still argue that the wording is sub-optimal. In other contexts, objects have a type. These metaobjects are types? In particular, a metaobject can be the type of an object, since you can construct an object of a metaobject. That just seems confusing to me.


I agree that the name 'metaobject' is confusing mainly because 'object' has several meanings in CompSci and even in the C++ standard; likewise 'meta' in 'metaprogramming'.

On the other hand the term 'metaobject' (and 'meta-level' vs. 'base-level') is pretty established in reflection terminology. We have considered other terms like 'meta-entity' (as if 'entity' is any clearer than 'object' :-P), 'meta-declaration', 'meta-expression',  'reflection' [noun], etc. but we eventually decided to stick with 'metaobject'.


Maybe we should call them meta types instead?

As I see it a meta-type is just a subset of a larger set of 'meta-objects' reflecting various "stuff" in the language.

 

However, to be consistent with the proposal, I will continue to call them metaobjects below.

*) Metaobjects are "opaque":
Earlier revisions of the proposal did not allow the creation of metaobject objects. Maybe then it made sense to just not say anything concrete about the metaobjects. 

However, now that we can construct them, we should say a bit more, I guess. For instance, it seemed like the most natural thing for me to create constexpr objects of metaobjects. The current proposal does not say whether that is legal.

IMO, the easiest way to go about it would be to say that metaobjects are empty structs. They have all the traits we need and we don't have to specify their behavior (other than in our concepts and traits). And the mystical opaqueness would just vanish.

I agree and we are planning to be more precise in this regard in the upcoming revision of P0194.
 

*) Namespace for metaobjects:
The proposal does not say anything about the namespace of metaobjects, but it would be helpful to know for ADL, for instance.

But since metaobjects are types, they can be reflected (so much for opaqueness, btw). So we can take a look at where they live in the experimental implementation: They reside in namespace std.

I believe that the proposal should specify the namespace for metaobjects and I believe that should be std::meta. For instance, we could then add constexpr functions in parallel to all the current traits (e.g. constexpr auto get_aliased_f(const T&) { return get_aliased_m<T>{}; }) that would work well with ADL.

The namespace (and the name) of metaobjects is intentionally left unspecified (at the moment, but see below).
What you are proposing can be easily achieved by wrapping the metaobject into a concrete template:

``
namespace libfoo {

template <std::meta::Object MO>
struct metaobject;

template <std::meta::Object MO>
constexpr auto get_aliased_f(metaobject<MO>) { ... };

}  // namespace libfoo
``

The Mirror reflection utilities [1] are using this technique without any problems.

[Note]
Currently the metaobjects are implemented as constexpr values of a special type `__metaobject_id` and the metaobjects themselves are implemented as:

``
template <__metaobject_id>
struct __metaobject { };
``

We are still debating whether we should expose this and make it part of the "official" interface. I personally think that it would be a good idea (even if it limits the implementations), Axel seems to disagree ;).
[/Note]

 

*) Reflecting (record) variables:
I understand from the examples in P0385R1 one of the main motivations for reflecting variables is obtaining their name. Also, I can 

  •  learn if the variable is static
  •  obtain a pointer (or class data member pointer) to it.

And I have the well known traits to know whether it is const or volatile.

Missing traits are IMO:

  •   is_constexpr
  •   is_inline
  •   has_default_value (in case of class members)

Such traits will be added in the future. At the moment we are focusing on convincing the committee that the overall idea of how we think reflection should be implemented is solid and reasonable. There is nothing preventing us from extending the interface later.

 
*) Namespaces:
Consider this program

#include <reflexpr>
#include <iostream>
#include <vector>
namespace foo
{
 
class bar{};
 
using V = std::vector<bar>;
}


int main()
{
  std
::cout << std::meta::get_display_name_v<std::meta::get_scope_m<reflexpr(V)>> << std::endl;
  std
::cout << std::meta::get_display_name_v<std::meta::get_scope_m<reflexpr(std::vector<foo::bar>)>> << std::endl;
}

It prints:

foo
std
::__1

`V`'s scope is `foo`, which seems obvious. `V`'s namespace is `std::__1`. This is also fine, because vector is actually declared inside the inline namespace `__` inside namespace std in libc++. Still, it is a bit surprising.

Again, it would be nice to have an `is_inline` trait to check whether a namespace is inline. That way I could choose to omit the `::__1` when printing the name, for instance.

I'm sorry, but at the moment the implementation of `get_display_name` operation is just a big mess and it is one of the major things on the TODO list. There is some machinery in clang (the TypeName::getFullyQualifiedName function) which would be very useful in implementing this, but it is not finished yet.

 

It might also be interesting to obtain associated namespaces. This might be useful for diagnostic purposes when trying to understand ADL for complex types/functions. See also next item.

This will be possible in the future. We didn't want to have template reflection in the initial proposal, but we are planning on adding it.
 

*) Template specializations:
Is there a way to obtain the arguments of a template specialization? For instance, 

using T = std::vector<int>


using MV = get_aliased_m<reflexpr(T)>;


Is there a way to learn that `MV` represents a template specialization of `std::vector` (or `std::__1::vector`) with `int` being the argument for the first template parameter, while the other parameters take their default arguments?

How can I compose the "display name" from the base names otherwise?

As mentioned above in the future it *will be* possible to reflect templates (and distinguish instantiation of templates), inspect their parameters, etc.
Also see the `get_full_name` operation [2] from the Mirror library.

[Note]
The whole "get-full-name" operation is problematic, because there is literally an infinite number of ways how to spell the name of something like `const std::vector<const std::string*>&`. The name can contain, spaces, tabs, newlines, the `const` and `volatile` qualifiers can appear in different places, etc.

I'm pretty certain that if we tried to standardize some platform-independent rendering of type names as a part of reflection it wouldn't go very well.

So we have decided that we will have the `get_display_name` operation which will be implementation-defined and that we provide the tools (the `get_base_name` operation) for the people so that they can write their own version of `get_full_name` to their own liking.
[/Note]
 

*) Alias or the real thing?
Consider this code:

#include <reflexpr>
#include <iostream>


template<typename T>
auto foo(const T& t)
{
  std
::cout << std::meta::get_base_name_v<reflexpr(T)> << std::endl;
}


int main()
{
  foo
(42);
}


This program prints `T`. I won't say that that is wrong, but I can say that it took me by surprise. I was expecting to see `int` (probably because I read that part of the proposal only afterwards).

Personally, I would prefer if the meta object yielded by `reflexpr(T)` represented `int` in this case and there were a meta function `template <typename T> struct get_alias<T>;` that provides a meta object representing the `T`.

I claim that `get_alias` to get the alias (e.g. `T`) would also be more intuitive than `get_aliased` to get the underlying type (e.g. `int`).

We have considered to add a similar operation -- `get_known_aliases` which would return a sequence of meta-aliases, reflecting all known aliases (template parameters, type aliases, namespace aliases, etc.), for a metaobject. I personally like the current interface more.

In any case it is possible to strip the alias pretty easily if it is not desired. Again the Mirror library shows how to implement this.

 

*) Suffix `_m`:
I find the suffix `_m` confusing rather than helpful. Those metafunctions return types. They are implemented as `template<typename T> using xxx_m = typename xxx<T>::type;`.

Why not use the canonical suffix `_t`? I understand it was like this before. I do not understand why it was changed to `_m`. Does not make much sense to me. Sure, they might be those special opaque meta types (see my first items), but they are still types.

We are considering turning `*_m` back to `*_t` in the next revision of P0194 and we will probably do that (although personally I find it useful being able to distinguish between operations returning "regular" types and operations returning metaobjects, I can live without it though).
 

*) get_base_classes/get_base_class/get_base_name:

  • get_base_classes takes a meta Class and returns a meta Sequence of meta Inheritances
    • it does not yield base classes, but inheritances
  • get_base_class takes a meta Inheritance and returns a meta Class
    • it does not yield a base class of an inheritance (no such thing)
  • get_base_name has nothing to do with inheritance at all, yet the current naming scheme seems to imply that.

Suggested renaming:
    s/get_base_classes/get_inheritances/
    s/get_base_class/get_class/

I expect these and other operation and concept names to be bikeshedded to death :).
 

*) is_class/is_struct:
I wonder if this distinction is really useful. The only difference between struct and class is the default accessibility of members and base classes, isn't it? And we can obtain the access specifiers of each member. So what's the point?

They are so interchangeable that a specialization of a template struct can be a class and vice versa.

Being able to distinguish between something declared as `class` and `struct` can be useful for code generators, where you need to copy a declaration precisely. In pedantic mode and with warnings as errors, generated code with mismatching declarations can fail to compile.
 

Also, there is a concept meta::Class but not meta::Struct.

We don't have a separate concept for class and struct for precisely the reasons that you have mentioned -- they are too alike. OTOH, as explained above, knowing how something was declared can be useful -- hence the traits.
 


So much for the moment. Thanks for reading :-)
 

Roland Bock

unread,
Jan 2, 2017, 4:17:01 PM1/2/17
to SG 7 - Reflection
Hi Matus,

Thanks for the quick reply!

Skipping the parts that are clear from your answers:


On Monday, January 2, 2017 at 9:26:09 PM UTC+1, Matúš Chochlík wrote:

On Mon, Jan 2, 2017 at 6:56 PM, Roland Bock <rb...@eudoxos.de> wrote:
*) Metaobjects are types:
Not being a language lawyer at all, I would still argue that the wording is sub-optimal. In other contexts, objects have a type. These metaobjects are types? In particular, a metaobject can be the type of an object, since you can construct an object of a metaobject. That just seems confusing to me.


I agree that the name 'metaobject' is confusing mainly because 'object' has several meanings in CompSci and even in the C++ standard; likewise 'meta' in 'metaprogramming'.

On the other hand the term 'metaobject' (and 'meta-level' vs. 'base-level') is pretty established in reflection terminology. We have considered other terms like 'meta-entity' (as if 'entity' is any clearer than 'object' :-P), 'meta-declaration', 'meta-expression',  'reflection' [noun], etc. but we eventually decided to stick with 'metaobject'.


Maybe we should call them meta types instead?

As I see it a meta-type is just a subset of a larger set of 'meta-objects' reflecting various "stuff" in the language.

Ah, so you're thinking of all the reflectable things and summarize them as objects, hence metaobjects.

I interpret the name from the user's perspective. What I receive from reflexpr() is type, therefore metatype.

In the end it is bike-shedding :-)
 


*) Namespace for metaobjects:
The proposal does not say anything about the namespace of metaobjects, but it would be helpful to know for ADL, for instance.

But since metaobjects are types, they can be reflected (so much for opaqueness, btw). So we can take a look at where they live in the experimental implementation: They reside in namespace std.

I believe that the proposal should specify the namespace for metaobjects and I believe that should be std::meta. For instance, we could then add constexpr functions in parallel to all the current traits (e.g. constexpr auto get_aliased_f(const T&) { return get_aliased_m<T>{}; }) that would work well with ADL.

The namespace (and the name) of metaobjects is intentionally left unspecified (at the moment, but see below).
What you are proposing can be easily achieved by wrapping the metaobject into a concrete template:

Sure, but then I need to do that in my library or use some 3rd party library, e.g. mirror.

I would like to see those functions in the standard, too, maybe in a later proposal. And then it might be useful to have pinned the namespace.

Do you really gain anything from not pinning the namespace?


[Note]
Currently the metaobjects are implemented as constexpr values of a special type `__metaobject_id` and the metaobjects themselves are implemented as:

 
``
template <__metaobject_id>
struct __metaobject { };
``

We are still debating whether we should expose this and make it part of the "official" interface. I personally think that it would be a good idea (even if it limits the implementations), Axel seems to disagree ;).
[/Note]

Personally, I'd rather specify the namespace than how the types are specified by the compiler. I don't really see what you might gain from the latter.
 
 

*) Alias or the real thing?
Consider this code:

#include <reflexpr>
#include <iostream>


template<typename T>
auto foo(const T& t)
{
  std
::cout << std::meta::get_base_name_v<reflexpr(T)> << std::endl;
}


int main()
{
  foo
(42);
}


This program prints `T`. I won't say that that is wrong, but I can say that it took me by surprise. I was expecting to see `int` (probably because I read that part of the proposal only afterwards).

Personally, I would prefer if the meta object yielded by `reflexpr(T)` represented `int` in this case and there were a meta function `template <typename T> struct get_alias<T>;` that provides a meta object representing the `T`.

I claim that `get_alias` to get the alias (e.g. `T`) would also be more intuitive than `get_aliased` to get the underlying type (e.g. `int`).

We have considered to add a similar operation -- `get_known_aliases` which would return a sequence of meta-aliases, reflecting all known aliases (template parameters, type aliases, namespace aliases, etc.), for a metaobject. I personally like the current interface more.

I've seen something like that in the revision history. Getting all known aliases would be overkill, I think. With a few nested namespaces and types this could explode quickly into something rather unwieldy.

I would stick with the variant you currently have: Make the "current" alias and the underlying type/namespace available. I would just change the initial focus to the underlying type/namespace.

In any case it is possible to strip the alias pretty easily if it is not desired. Again the Mirror library shows how to implement this.

Sure, that was the first wrapper I wrote myself :-)
 

*) Suffix `_m`:
I find the suffix `_m` confusing rather than helpful. Those metafunctions return types. They are implemented as `template<typename T> using xxx_m = typename xxx<T>::type;`.

Why not use the canonical suffix `_t`? I understand it was like this before. I do not understand why it was changed to `_m`. Does not make much sense to me. Sure, they might be those special opaque meta types (see my first items), but they are still types.

We are considering turning `*_m` back to `*_t` in the next revision of P0194 and we will probably do that (although personally I find it useful being able to distinguish between operations returning "regular" types and operations returning metaobjects, I can live without it though).

I'd claim that metaobjects actually are regular types. Their special powers come from concepts and meta-functions. Anyway, good to read that you're considering going back to `*_t`.


Best,

Roland
 

Hal Finkel

unread,
Jan 2, 2017, 8:56:12 PM1/2/17
to refle...@isocpp.org
If I correctly recall the discussion, supporting the construction of pretty-printing logic using template metaprogramming turned out to be something we specifically wanted to discourage. Pretty printing is complicated and modern compilers already have sophisticated, and sometimes system-specific, logic for this purpose. Providing programmatic access to that logic was discussed favorably, but trying to reconstruct that kind of logic in template metaprograms was predicted to lead to sub-par outcomes.

 -Hal

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

-- 
Hal Finkel
Lead, Compiler Technology and Programming Languages
Leadership Computing Facility
Argonne National Laboratory

Matus Chochlik

unread,
Jan 3, 2017, 1:48:43 AM1/3/17
to refle...@isocpp.org
Hi,

On Mon, Jan 2, 2017 at 10:17 PM, Roland Bock <rb...@eudoxos.de> wrote:

On Monday, January 2, 2017 at 9:26:09 PM UTC+1, Matúš Chochlík wrote:

I agree that the name 'metaobject' is confusing mainly because 'object' has several meanings in CompSci and even in the C++ standard; likewise 'meta' in 'metaprogramming'.

On the other hand the term 'metaobject' (and 'meta-level' vs. 'base-level') is pretty established in reflection terminology. We have considered other terms like 'meta-entity' (as if 'entity' is any clearer than 'object' :-P), 'meta-declaration', 'meta-expression',  'reflection' [noun], etc. but we eventually decided to stick with 'metaobject'.


Maybe we should call them meta types instead?

As I see it a meta-type is just a subset of a larger set of 'meta-objects' reflecting various "stuff" in the language.

Ah, so you're thinking of all the reflectable things and summarize them as objects, hence metaobjects.

I interpret the name from the user's perspective. What I receive from reflexpr() is type, therefore metatype.

In the end it is bike-shedding :-)

I care much more for the functionality than for any particular concept/operation names. If we want to invent our own reflection terminology -- fine -- just let's not get stuck in endless academic discussions over things which are for the most part matter of personal taste, postponing the implementation of reflection in C++.

 
 


*) Namespace for metaobjects:
The proposal does not say anything about the namespace of metaobjects, but it would be helpful to know for ADL, for instance.

But since metaobjects are types, they can be reflected (so much for opaqueness, btw). So we can take a look at where they live in the experimental implementation: They reside in namespace std.

I believe that the proposal should specify the namespace for metaobjects and I believe that should be std::meta. For instance, we could then add constexpr functions in parallel to all the current traits (e.g. constexpr auto get_aliased_f(const T&) { return get_aliased_m<T>{}; }) that would work well with ADL.

The namespace (and the name) of metaobjects is intentionally left unspecified (at the moment, but see below).
What you are proposing can be easily achieved by wrapping the metaobject into a concrete template:

Sure, but then I need to do that in my library or use some 3rd party library, e.g. mirror.

I would like to see those functions in the standard, too, maybe in a later proposal. And then it might be useful to have pinned the namespace.

Do you really gain anything from not pinning the namespace?

One thing is that it would make that namespace (like `std::meta` and that means also `std` itself) "magic" and defined by the compiler. I'm not sure I want to go there and off the top of my head I don't recall any precedent for this.
 


[Note]
Currently the metaobjects are implemented as constexpr values of a special type `__metaobject_id` and the metaobjects themselves are implemented as:

 
``
template <__metaobject_id>
struct __metaobject { };
``

We are still debating whether we should expose this and make it part of the "official" interface. I personally think that it would be a good idea (even if it limits the implementations), Axel seems to disagree ;).
[/Note]

Personally, I'd rather specify the namespace than how the types are specified by the compiler. I don't really see what you might gain from the latter.

The latter would make implementation of a constexpr-metaprogramming (which seems to be taking off) interface and even some of the TMP operations on top of our proposal easier (and probably more efficient).
 
 
I claim that `get_alias` to get the alias (e.g. `T`) would also be more intuitive than `get_aliased` to get the underlying type (e.g. `int`).

We have considered to add a similar operation -- `get_known_aliases` which would return a sequence of meta-aliases, reflecting all known aliases (template parameters, type aliases, namespace aliases, etc.), for a metaobject. I personally like the current interface more.

I've seen something like that in the revision history. Getting all known aliases would be overkill, I think. With a few nested namespaces and types this could explode quickly into something rather unwieldy.

I would stick with the variant you currently have: Make the "current" alias and the underlying type/namespace available. I would just change the initial focus to the underlying type/namespace.

In the end, someone will have to do the additional work of either calling `get_aliased` or `get_alias`. I'm not sure at the moment which one will be more frequent. But I see the current approach more consistent:
``
get_base_name_v<reflexpr(int)>  // "int"
get_base_name_v<reflexpr(std::string)>  // "string"
get_base_name_v<reflexpr(T)>  // "T" (in a template)
``

However what I think is very important here, is that (directly reflected) aliases have their own distinct identity in the reflection facility.
 

In any case it is possible to strip the alias pretty easily if it is not desired. Again the Mirror library shows how to implement this.

Sure, that was the first wrapper I wrote myself :-)

And one may easily become part of the standard interface in the future :)
 
 
BR,
 
--Matus

Matus Chochlik

unread,
Jan 3, 2017, 2:01:24 AM1/3/17
to refle...@isocpp.org
On Tue, Jan 3, 2017 at 2:56 AM, Hal Finkel <hfi...@anl.gov> wrote:

On 01/02/2017 11:56 AM, Roland Bock wrote:

*) Namespaces:
Consider this program

#include <reflexpr>
#include <iostream>
#include <vector>
namespace foo
{
 
class bar{};
 
using V = std::vector<bar>;
}


int main()
{
  std
::cout << std::meta::get_display_name_v<std::meta::get_scope_m<reflexpr(V)>> << std::endl;
  std
::cout << std::meta::get_display_name_v<std::meta::get_scope_m<reflexpr(std::vector<foo::bar>)>> << std::endl;
}

It prints:

foo
std
::__1

`V`'s scope is `foo`, which seems obvious. `V`'s namespace is `std::__1`. This is also fine, because vector is actually declared inside the inline namespace `__` inside namespace std in libc++. Still, it is a bit surprising.

Again, it would be nice to have an `is_inline` trait to check whether a namespace is inline. That way I could choose to omit the `::__1` when printing the name, for instance.

If I correctly recall the discussion, supporting the construction of pretty-printing logic using template metaprogramming turned out to be something we specifically wanted to discourage. Pretty printing is complicated and modern compilers already have sophisticated, and sometimes system-specific, logic for this purpose. Providing programmatic access to that logic was discussed favorably, but trying to reconstruct that kind of logic in template metaprograms was predicted to lead to sub-par outcomes.

That may be the case (although this is the first time that I hear that any such discussion took place, having only attended the Oulu meeting in person), and this is one of the reasons why a platform independent `get_full_name` is not part of our current proposal.

If someone just wants to print a platform-dependent pretty full type name to display to the user, they can use `get_display_name` - implemented in the compiler.

If anyone really needs a platform-independent full type name to be used in TMP metaprogramming, they can do so as demonstrated by the Mirror library, even if at some compile-time cost. If it turns out that this use case is frequent, a `get_full_name` operation implemented by an compiler intrinsic can be easily added later without slowing down the inclusion of out proposal into the standard.
If someone is willing to go through the process of defining the rules for such type name rendering and pushing it through the committee, they are free to do that and I wish them luck ;)

Also if someone just needs the platform-independent full type name at runtime or in constexpr MP, that also can be done, but with lower impact on compilation times.

BR,
 
--Matus

Roland Bock

unread,
Jan 3, 2017, 2:57:47 AM1/3/17
to refle...@isocpp.org
Hi Matus,

Thanks for your explanations :-)

Looking forward to future iterations.

Cheers,

Roland

PS: Let me know if I can help, e.g. by testing or reading
> *_*) Namespace for metaobjects:_*
> --
> 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>.

Matus Chochlik

unread,
Jan 3, 2017, 3:38:10 PM1/3/17
to refle...@isocpp.org
Hi Roland,

On Tue, Jan 3, 2017 at 8:57 AM, Roland Bock <rb...@eudoxos.de> wrote:
Hi Matus,

Thanks for your explanations :-)

Hopefully they were helpful ;)
 

Looking forward to future iterations.

Cheers,

Roland

PS: Let me know if I can help, e.g. by testing or reading

Thanks for the feedback so far, I'll fix the remaining issues on github shortly. If you spot any other problems with the implementation please file a bug report again.

--Matus
 

Reply all
Reply to author
Forward
0 new messages