In a project, I have a C-API which uses C-style function pointers as callbacks. In one of those callbacks, I need to access a private function of an object Foo. Note that the API-call is done within a function of my class. Because of not shown code, I have a handle to my object as a void* accessible to me.
Things aside that the construct is prone to errors, by passing a lambda as callback I am able to access the private function of my object.
This is somewhat unexpected but welcome to me. I haven't found anything regarding this behavior, so I would kindly ask if somebody could shed some light why this is actual working. I am not aware that the lambda is catching something, but it appears that is has something to do with the actual scoping.
I am using C++17 and gcc 10.2.
Here's a sample block of code:
void TestFunc(void (*)(void*)) {
}
class Foo {
public:
Foo() {
TestFunc([](void* handle){
auto foo = reinterpret_cast<Foo*>(handle);
foo->BarFunc();
});
};
private:
void BarFunc() {};
};
Your code is working because Standard allows it. So first we have this (C++20 [expr.prim.lambda.closure]p2):
The closure type is declared in the smallest block scope, class scope,
or namespace scope that contains the corresponding lambda-expression.
<...>
And in your example we have a block scope so in the end we have an unnamed local class declaration and according to [class.local]p1:
A class can be declared within a function definition; such a class is
called a local class. The name of a local class is local to its
enclosing scope. The local class is in the scope of the enclosing
scope, and has the same access to names outside the function as does
the enclosing function
Related
In my current project I am trying to pass a private member function as parameter to another function. In my code, the other function is a member function of a different class, but for keeping it simple, here it is a free function.
void outside_function(std::function<void(int)> func) {
// do something with func
}
class MyClass {
public:
void run();
private:
bool my_func(double); // defined in source file
};
Now, from inside run I want to put my_func into outside_function as argument. Since the signature of run does not fit the requirements for the parameter, I cannot simply pass it. Using the adapter pattern was my first try, which was when I was reminded that member functions implicitly take the this pointer as first argument. This answer suggests using a lambda expression, which is what I did.
void MyClass::run() {
outside_function([this](int a) -> void {
double d = static_cast<double>(a);
this->my_func(d);
});
}
Why does this work? From my point of understanding, outside_function does not have access to my_func. Why don't I have to make my_func public first? Is it something the compiler does or some C++ rule I don't know?
Additionally, are there any catches to this approach that might break my code?
private access specifier only restrict an object name to be visible (it cannot be looked up) outside the class. The object itself is like any other member.
[class.access]/1
A member of a class can be
(1.1) private; that is, its name can be used only by members and friends of the class in which it is declared.
(1.2) protected; that is, its name can be used only by members and friends of the class in which it is declared, by classes derived from that class, and by their friends (see [class.protected]).
(1.3) public; that is, its name can be used anywhere without access restriction.
outside_function never accesses the member (it only knows the type of the func parameter and can't possibly care about how it's defined) -- only the lambda function does.
Since you're defining the lambda function inside MyClass, you can access all the private names within it.
outside_function calls the provided function, but if you weren't allowed to call a function that uses any private members, you couldn't do much.
I have a following snippet code of c++. Declared a class inside main() function.
What is the reason to we can not define friend function in local class?
#include<iostream>
int main()
{
class Foo
{
void foo() {} // Ok
friend void Bar(){}; // Error
};
}
There's a practical reason. First and foremost, an inline friend definition cannot be found by either qualified or unqualified lookup. It can only by found by ADL. So if we take the class from your example, put it in global scope and try to call Bar:
class Foo
{
friend void Bar(){};
void foo() {
Bar();
}
};
We'll be notified that Bar was not declared in that scope. So if it was in a local class. You can't call it from the members. You can't call it inside the function. The only way you may call it involves either some hoops or ADL. So the language just doesn't allow for it. It's not deemed a useful feature.
There is no convincing technical reason for this. ADL can't find it, you say? Well, that's basically part of the question: why can't ADL find it? Just extend ADL to make it find it.
One design-level reason for this limitation is probably rooted in the language treatment of unqualified names in friend declarations.
Unqualified names used in friend declarations in local classes refer to names from nearest enclosing non-class scope. This treatment of unqualified names is critically important, since this is the only way local classes can refer to each other (since for obvious reasons, local classes do not have qualified names)
int main()
{
class B;
class A {
int x;
friend B; // refers to local `B`
};
class B {
void foo(A &a) { a.x = 42; }
};
}
This rule is also applied to friend function declarations with unqualified names. C++ does not have local functions, but such friend declarations can still refer to a local non-defining declaration of a function (which is perfectly legal)
void foo() {}
int main()
{
void foo(); // refers to `::foo`
class A {
friend void foo(); // refers to local `foo`, which is `::foo`
};
}
Now, what would you propose should happen when one defines a friend function in a local class (using an unqualified name, of course)? What function is introduced by such a declaration? Into what scope, specifically? By definition, it is not a member of the class, since friend declarations do not introduce class members. It cannot be a member of the nearest enclosing local scope, since that would make it a local function and C++ does not support local functions.
We cannot just uniformly change the behavior of all unqualified names in friend declarations and say that they should now refer to names in the nearest enclosing namespace scope, since that would leave as with no way to refer to local classes (as shown above).
The only way out of this situation is to make only in-class friend function definitions refer to (and define) functions in the nearest enclosing namespace scope. Such functions would only be callable through [modified] ADL (and let's say we are OK with that). But that would mean that we'd have to give different treatment to unqualified names in friend function definitions (as opposed to non-defining friend declarations). This would be rather inelegant and confusing. So, the language authors decided against it.
Note that importance of this might have increased notably after C++14, which gave us deduced auto return types in functions. After that local classes became not even nearly as "local" as they used to be
auto foo()
{
struct S // Local class
{
void bar() {}
};
return S();
}
int main()
{
auto a = foo();
a.bar(); // An object of local class used outside of its original scope
typedef decltype(a) S; // Local type is "stolen" from its original scope
S b; // and used to freely declare objects in a completely
b.bar(); // different scope
}
Because member functions of a local class have to be defined entirely inside the class body and friend function not a member function. We declared friend functions inside class and defined outside of class.
According to cppreference:
Local classes
A local class cannot have static members
Member functions of a local class have no linkage
Member functions of a local class have to be defined entirely inside the class body
Local classes other than closure types (since C++14) cannot have member templates
Local classes cannot have friend templates
Local classes cannot define friend functions inside the class definition
A local class inside a function (including member function) can access the same names that the enclosing function can access.
I have public member functions which are calling private member function. I want to limit the scope of the private member function within the file where definition of private member function is available. In C, I used static before the function name to limit its scope within the file, how do I achieve it in C++.
class Base
{
public:
void XYZ1(void);
void XYZ2(void);
private:
void fun(void);
};
void Base::XYZ1(void)
{
fun();
}
void Base::fun(void)
{
// do something;
}
Now if the member function XYZ2 is defined in some other .cpp file , it should not be allowed to call fun() from it. Basically restrict the fun() function to file scope.
In a1.cpp
void Base::XYZ2(void)
{
fun();// this should result in some error saying fun() is not defined in its scope.
}
I want to limit the scope of the private member function within the file where definition of private member function is available.
A private member function cannot be used by another class or function unless they are granted friend-ship by the class. In that sense, the scope in which the function can be called is already limited.
Having said that, any member function of the class or any class or function that has been granted friend-ship by the class will be able to call the private member function.
The only way to prevent that function from being called outside the file in which it is defined is to make it a non-member static function in the .cpp file. or put it in an anonymous namespace in the .cpp file.
Now if the member function XYZ2 is defined in some other .cpp file ,
it should not be allowed to call fun() from it. Basically restrict the
fun() function to file scope. In a1.cpp
You can put the function in an anonymous namespace (in the cpp file where used). The linkage will become internal, and the name won't be available for access from any other file. One can get the same effect when making the function static (in the cpp file).
If you need to access internal/private members, you could use a nested class who's implementation is defined in the associated cpp file:
//h
class Nesting
{
//...
private:
struct MyPrivateFunctions;
};
//cpp
struct Nesting::MyPrivateFunctions
{
static void f1(Nesting& this);
static void f2(Nesting& this);
//etc...
};
I've passed Nesting as parameter that MyPrivateFunctions may access its private members (since it is nested, this is permitted).
Note that this is very similar to the Impl trick mentioned elsewhere, but it also allows independent member function definitions in other units, and it does not need instantiation.
Most people are suggesting you to use anonymous namespace in C++. But, this would only be feasible if you wanted to do something like, declaring a global variable/function which is supposed to be used strictly inside the file under which it is defined.
We cannot use namespace within the class as per C++ standards, for which you may want to take a look at this discussion: Why can't we declare a namespace within a class?
I used static before the function name to limit its scope within the file.
This worked for you but the understanding here is wrong as static was never intended to be used as scope specifier, its a storage specifier and its lifetime is throughout the program life. You can still access the static variable from other files in several ways, however the compiler here does not provide an externally visible linker symbol and thus cannot be accessed by other translation units / files.
As per the public member functions are concerned they should be allowed to use this private function from whichever file it is defined in. So that the relation between the class member functions are not destroyed. I suppose you would now stop treating static as scope specifier :)
Or you can use the good old Impl- trick if you do not want to show the "hidden" functions of a class to the outside. Private functions are still listed in the header file, after all.
// Foo.h
class FooImpl; // forward declearation
class Foo
{
FooImpl *m_pImpl;
public:
Foo(); // Default constructor (and any other) create instance of FooImpl.
~Foo();
};
// Foo.cpp
class FooImpl
{
// members of hidden types, secrets, methods, ... anything you do not want to show to users of class Foo.
};
Foo::Foo() : m_pImpl(new FooImpl()) {}
Foo::~Foo()
{
delete m_pImpl; m_pImpl = nullptr;
}
As can be seen, with the impl trick you cannot only hide functions, but also data members of a class and type dependencies which would be incurred if the members were part of Foo class.
A way to solve this problem is by using a so called 'facade'. Basically, you have two classes: The first class has the private method which you want to hide, where as the second class implements a wrapper which just provides the methods you want to be accessible. The second class wraps an instance of the first. That's how the whole trick works.
https://en.wikipedia.org/wiki/Facade_pattern
So I was learning about classes and I stumbled upon something I found was quite awkward to me.
class Nebla
{
public:
int test()
{
printout();
return x;
}
void printout()
{
printout2();
}
private:
int x,y;
void printout2()
{
cout<<"Testing my class";
}
};
I found that in a class I can use functions before I declare them (prototype them)
You can see I used printout() , printout2() before decleration.
And I can use variables also before declaring them
You can see I did return x; before declareing x.
Why can I use functions and variables in classes before declaration but outside the class if I do that, I get an error?
Thanks
Good question; I've relied on that feature for years without thinking about it. I looked through several C++ books to find an answer, including Stroustrup's The C++ Programming Language and The Annotated C++ Reference Manual, but none acknowledge or explain the difference. But, I think I can reason through it.
The reason, I believe, that your example works is that the bodies of your test and printout aren't truly where they appear in your file. The code
class MyClass {
void someFun() {
x = 5;
}
int x;
};
...which appears to violate the rule of having to declare variables before you use them, is actually equivalent to:
class MyClass {
void someFun();
int x;
};
void MyClass::someFun() {
x = 5;
}
Once we rewrite it like that, it becomes apparent that the stuff inside your MyClass definition is actually a list of declarations. And those can be in any order. You're not relying on x until after it's been declared. I know this to be true because if you were to rewrite the example like so,
void MyClass::someFun() {
x = 5;
}
class MyClass {
void someFun();
int x;
};
...it would no longer compile! So the class definition comes first (with its complete list of members), and then your methods can use any member without regard for the order in which they're declared in the class.
The last piece of the puzzle is that C++ prohibits declaring any class member outside of the class definition, so once the compiler processes your class definition, it knows the full list of class members. This is stated on p.170 of Stroustrup's The Annotated C++ Reference Manual: "The member list defines the full set of members of the class. No member can be added elsewhere."
Thanks for making me investigate this; I learned something new today. :)
Just to make it clear, this is required by the C++ Standard, not just the way several compilers handle class definitions.
N3242 3.3.7:
The potential scope of a name declared in a class consists not only of the declarative region following the name's point of declaration, but also of all function bodies, brace-or-equal-initializers of non-static data members, and default arguments in that class (including such things in nested classes).
The reason you are able to do this is because by the time you call test, printout or printout2, they will have already been created. If you call the function outside the arbitrary function before it's implementation, then you'll get an error.
Think of class member-functions as being asynchronous with the flow of evaluation of the rest of the class. This won't work with stand alone functions, but you can access data members that haven't been instantiated yet. I'm not completely sure why we are able to do this, but I think it has to do with instantitation of the class object.
Besides Philip's good response, Stroustrup gives a nice explanation of Name Lookup Rules in The Design and Evolution of C++. This is described in "6.3 Clarifications". In 6.3.1.1, "The ARM Name Lookup Rules", he mentions 2 rules defined in the ARM:
[1]The type redefinition rule:A type name may not be redefined in a class after it has been used there.
[2] The rewrite rule: Member functions defined inline are analyzed as if they were defined immediately after the end of their class declarations.
So in your case it would apply the rewrite rule (as Philip deduced), that's why you can forward reference those class members.
This book may be mainly of historical interest (it's written in '94), but I think those rules are applied the same way today.
Why can I use functions and variables in classes before declaration
This is because the body of a member function is a complete-class context of a class, as mentioned in the quoted statements below:
From class.mem.general#6:
6. A complete-class context of a class is a:
function body ([dcl.fct.def.general]),
default argument,
noexcept-specifier ([except.spec]), or
default member initializer
within the member-specification of the class.
This means that the usage of printout inside member function test and the usage of printout2 inside member function printout is allowed here even though those members appear later when writing the class definition.
I am trying to do the following: Obtain the address of a member function from a class that was locally defined within a function.
class ConnectionBase
{
};
template class<EventType, SinkType>
class ConnectionImpl : public ConnectionBase
{
public:
typedef void (SinkType::*EventCallback)(EventType const&);
};
template<class EventType>
class Source
{
template <class SinkType>
boost::shared_ptr<ConnectionBase> setupCallback(typename ConnectionImpl<EventType, SinkType>::EventCallback func, SinkType* sink)
{
// do the actual connecting.
}
};
class SomeClass
{
public:
void someFunction(int const& event){}
}
class SomeUnitTest
{
public:
void someTest()
{
class NestedClass
{
public:
void someFunction(int const& event){}
};
NestedClass nc;
//Try#1 - This does not work
setupCallback<int, NestedClass>(&NestedClass::someFunction, &nc);
//Try #2 - This also does not work
setupCallback<int, NestedClass>(&SomeUnitTest::someTest::NestedClass::someFunction, &nc);
//Try #3 - Following the GCC error output, I tried this
setupCallback<int, NestedClass>(&SomeUnitTest::someTest()::NestedClass::someFunction, &nc);
SomeClass sc;
//This works fine, as expected
setupCallback<int, SomeClass>(&SomeClass::someFunction, &sc);
}
};
Try #2 and #3 utterly confuse GCC, it has no idea what I am trying to do.
Try #1 produces a more helpful error message saying no setupCallback exists that takes the form "setupCallback(void (SomeUnitTest::someTest()::NestedClass::SomeFunction::*), etc)
Which is how try #3 was born.
I can't really find a lot of information about classes defined inside a function, does anyone know the correct syntax for this, and maybe have a resource that discusses this topic?
Ok, it appears this is settled, as both posters have pointed out, local classes have no linkage, it can't work. Now knowing this, I found this article that discusses this, for anyone else that runs into this problem and stumbles across this question: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=420
Edit:
Clarification of setupCallback(), working example with a more regular class
Edit #2:
Updated wording to change "nested" to "local". Added more detail for setupCallback.
Edit #3: Added links to furhter information. Thanks everyone.
I don't know about the syntax problem, the usual access rules should apply - but there is another problem here if that would work as these member functions have no linkage.
To accept local types at all, setupCallback() would have to be a template function - but template type arguments with no linkage are not allowed.
§3.5/8 says:
Names not covered by these rules have
no linkage. Moreover, except as noted,
a name declared in a local scope
(3.3.2) has no linkage.
Members of local classes are not covered there. §9.3/3 clarifies that:
Member functions of a local class
(9.8) have no linkage.
Long story cut short: don't use member functions of a local class as callbacks, use a non-local class instead.
You fist variant is the correct one as long as the specific matter of taking the address is considered. There are no restrictions on taking the address of member functions of local classes. The proper syntax is the usual
&NestedClass::someFunction
ans that's it. You can try saving it in an intermediate pointer in your code
void (NestedClass::*ptr)() = &NestedClass::someFunction;
and I'm sure your compiler will accept it.
However, the problem I suspect exists in your code has absolutely nothing to do with the proper way of taking the address of a member function. It is rather about the way the first parameter of setupCallback is declared. Since you say it works with &SomeClass::someFunction as the first argument, I'd expect setupCallback to be declared as
void setupCallback(void (SomeClass::*cb)(), SomeClass *p); // one possibility
i.e. it is hardcoded to expect a pointer to a member of SomeClass specifically. You cannot supply a pointer to a member of NestedClass instead. NestedClass is completely unrelated to SomeClass and pointers to members of NestedClass are completely incompatible with pointers to members of SomeClass. This is why it won't compile.
Unless there's something you are not showing us (like setupCallback being a function template maybe? Or overloaded for different parameter types?), what you are trying to do is simply impossible to achieve regardless of how you take the member address, as long as NestedClass remains unrelated to SomeClass. Function setupCallback is designed to work with SomeClass and SomeClass only.
Provide more information about setupCallback. How is it declared?
Note that if the setupCallback is declared as a function template parametrized by class type, as in
template <class T> void setupCallback(void (T::*cb)(), T* p);
then you won't be able to use the local class NestedClass as template argument for parameter T. In this case the fact that your NestedClass has no linkage does indeed come into play. But, again, it has nothing to do with taking the member address, but rather caused by the fact that classes with no linkage cannot be used as template arguments in C++.