Is there a reason why we cannot name a non-stationary member function in an invaluable context?

Reading [expr.prim.id] shows that

An identifier that denotes a non-static data element or non-static function of a class member can be used only:

  • if this id expression denotes a non-static data element and it appears in an unvalued operand.

The fact that the bullet above applies only to data members is unclear to me. Intuitively, I expect the following to be well-formed:

#include <type_traits> using func = int(); class bar { func foo; // This is valid, and not the subject of the question }; static_assert(std::is_same<decltype(bar::foo), func>::value, "No Symmetry!"); 

But decltype() poorly developed even before checking for a static statement.

Is there any ambiguity that I'm missing?

+7
c ++ language-lawyer
source share
3 answers

Is there any ambiguity that I'm missing?

In fact, there is a lot of type information that is added as part of the declaration of this member function.

Although func can certainly be used to announce this member, the story does not end here. Once a member is declared, it is filled. This includes the addition of several other things, such as cv-qualifers and ref-qualifiers. In the case of foo , all implicit ones are defined by default, and they become part of the type bar::foo . As indicated by [dcl.fct] / 8 :

The return type, the list of parameter parameters, ref-qualifier, cv-qualifier-seq and the exception specification, but not the default arguments, are part of the function type.

It is not possible to explicitly specify them in the above declaration of foo (although they can be added to func ), but they can be added at all:

 class bar { int foo() const volatile &&; }; 

They are part of the function type, and decltype(bar::foo) should access them if they appear (and if I am going to correctly, even if they do not).

Where does const volatile && go when we try to evaluate decltype(bar::foo) ?

  • Should I ignore it? It can be done. But losing type information is rarely good.
  • Should we save it, and decltype is considered a pointer to a member function instead?
    This will work too, but now it is different from how data members will act when named in an invaluable context. We introduce the discrepancy.
  • Should it be saved and the type resolved to something else? Perhaps something like int(foo const volatile&&) or int() const volatile && (another form of function type)? This violates the symmetry that might be expected, and again is a mismatch of the data members.

There is no simple or obvious way to always work well. Therefore, instead of complicating matters for a function that will have limited use, it is better to consider it as poorly formed.

+1
source share

Is there any ambiguity that I'm missing?

I do not think so. Most likely, there is a certain need to evaluate non-static data elements and not so much for non-static member functions.

However, this:

 static_assert(std::is_same<decltype(bar::foo), func>::value, "No Symmetry!"); 

doesn't make much sense. Type &bar::foo not func* , it func bar::* . And there is no way to write this without a pointer, so being able to evaluate decltype(bar::foo) means introducing all the syntax of the new type? It doesn't seem to be worth it.

Note that decltype(bar::foo) cannot be func because func is a type of function, but bar::foo is a member function.

0
source share

I see no reason.

Look at this:

 typedef void Func(); Func freeFunction; struct Foo { Func memberFunction; }; 

freeFunction Announcement Func freeFunction; . So decltype(freeFunction) is void() , i.e. Func .

Using the same logic, As Foo::memberFunction also declared as Func , I expect decltype(Foo::memberFunction) be Func too. But this is not so, as it does not compile.

Just like int a; decltype(a) int a; decltype(a) resolves int , even if int a; is a member, decltype(Foo::memberFunction) should be fine.

Note that qualifiers can also be processed, there is nothing special about them (of course, in this case Func can only be used to declare non-static member functions):

 typedef void Func() const volatile &&; struct Foo { Func memberFunction; }; 

Here I expect decltype(Foo::memberFunction) be void() const volatile && , so I can copy its declaration:

 struct Bar { decltype(Foo::memberFunction) myMemFn; }; 

Quote from the C ++ 14 standard (9.2 / 11):

[Note. The type of the non-static member function is the regular type of the function, and the type of the non-static member is the regular type of the object. There are no special types of member functions or data types. - final note]

This quote means that it would be reasonable if decltype(<member_function>) returned the type of a regular function.

-one
source share

All Articles