Showing posts with label cpp_name_resolution. Show all posts
Showing posts with label cpp_name_resolution. Show all posts

Nov 6, 2024

[C++] name look up minor refresh

One colleague mentioned in the chat; why accessing private inherited base type inside the derived type member function results in access control failure "'BaseType' is a private member of 'BaseType'"?

i.e. https://godbolt.org/z/hWef37sT9

It turns out from the basic name resolution logic in the language which refer to ISO 6.5 : https://timsong-cpp.github.io/cppwp/basic.lookup.unqual


To summarize:

  • Name lookup
    This is the process by which the compiler determines the meaning of a name, without regard to access permissions. This lookup will find the declaration or definition of the name in the applicable scopes (namespace, class, or enclosing function).
  • Access control
    After name lookup has identified the entity, the compiler checks access control to determine whether it is permissible to use the entity based on access specifiers like public, protected, or private.

In essence, the sequence is:

  1. First, perform name lookup.
  2. Then, check access control on the resolved name.

Thus simply solution goes to:
class PrivateBase {
};

class Middle: private PrivateBase {
};

class Child: public Middle {
    ::PrivateBase Fooey() {
        return ::PrivateBase();
    }
};

Nov 13, 2022

[C++] function overload resolution in one GIF (by Jeff Preshing)

While C++'s function overload resolution is perplex, Jeff Preshing had a way to explain it in one GIF.

Although there are sophisticated details (e.g. ADL, pointer to function;pointer to member function etc.) which should be known by seasoned C++ engineers, the GIF provides a quick look-up for code that hits ambiguous resolution state.

Reference:
https://preshing.com/20210315/how-cpp-resolves-a-function-call/


credit: Jeff Preshing



Aug 19, 2018

[C++17] casting derived type member function to base type signature

https://ibob.github.io/blog/2018/08/18/a-bug-in-the-cpp-standard/

Interestingly if simply using:
template<auto MemFunc>
void run(Derived& d){
 (d.*MemFunc)();
}

would not have any issue, and that's exactly first thing pop up in my head.
However, just because the author tried other approach could this limitation being revealed :-)

tl;dl;
Below in main, code won't work:

iamproxy<static_cast<void (Base::*)()>(&Derived::brun)>(d);

explained why:
https://groups.google.com/a/isocpp.org/forum/embed/?place=forum/std-discussion#!topic/std-discussion/__QDbLgpFik

quoted:
The code is valid, but the Itanium C++ ABI does not specify a mangling for it yet, so compilers targeting that ABI tend to not accept it yet.
Clang produces a "sorry, not supported yet" error if you try this with a class template, but unfortunately you only get a generic "bad template arguments" error in the function template case.
#include <iostream>

using namespace std;


struct Base {
    void brun()
    {
        cout << "brun" << endl;
    }
};

struct Derived : Base {
    void drun()
    {
        cout << "drun" << endl;
    }
};


template <void (Base::*PTR)()>
void iamproxy(Derived &de)
{
    cout << "in test" << endl;
    (de.*PTR)();
}


int main()
{
    Derived d;
    iamproxy<static_cast<void (Base::*)()>(&Derived::brun)>(d);
}

In templates, there's no implicit type casting.
The non-type, type, template template should be exactly type match.
This is unlike runtime implicit casting,
i.e passing derived member function, either virtual / non-virtual non-static member function to functions taking pointer to based member function.

Above casting error message happens on virtual member function as well, due to same name mangling issue,
i.e, it can't even instantiate the template function.

Additional reference:
https://vsdmars.blogspot.com/2014/05/c-function-overload-resolution-is.html

May 5, 2014

[C++] function overload resolution is completed inside a struct/class scope

1.
function overload resolution is completed inside a struct/class scope, also before virtual function dispatch.

Code below member ‘fun’ is ambiguous

struct Dummy{};                                                                           
                                                                                          
struct Base1                                                                              
{                                                                                         
   virtual void fun(int)                                                                  
   {                                                                                      
   }                                                                                      
};                                                                                        
                                                                                          
struct Base2                                                                              
{                                                                                         
   virtual void fun(Dummy){}                                                              
};                                                                                        
                                                                                          
                                                                                          
struct De : Base1, Base2                                                                  
{                                                                                         
};                                                                                        
                                                                                          
                                                                                          
int main()                                                                                
{                                                                                         
   De d;                                                                                  
   d.fun(Dummy());                                                                        
}   

2.
function overload resolution happens in sequence, which can't goes back.
Like SFINAE

--
If the resulting set of declarations are 

1. not all from sub-objects of the same type,

2. or the set has a non-static member and includes members from distinct sub-objects,

there is an ambiguity and the program is ill-formed. 
Otherwise that set is the result of the lookup.

Reference:
Name resolution and overloading
Function with parameter type that has a copy-constructor with non-const ref chosen?