What does explicit *this object parameter offer in C++23? - c++

In C++23, deducing this is finally added to the standard.
Based on what I've read from the proposal, it opens up a new way of creating mixins, and possible to create recursive lambdas.
But I'm confused if this parameter creates a "copy" without using templates since there is no reference or does the explicit this parameter have its own rules of value category?
Since:
struct hello {
void func() {}
};
may be the equivalent of:
struct hello {
void func(this hello) {}
};
But their type is different because for &hello::func, the first one gives void(hello::*)(), while the second one gives void(*)(hello)
For instance, I have this simple function:
struct hello {
int data;
void func(this hello self) {
self.data = 22;
}
};
Doesn't this parameter need to be a reference to change the value of hello type? Or it basically follows the cv-ref qualifier rules of member function as same as before?

Section 4.2.3 of the paper mentions that "by-value this" is explicitly allowed and does what you expect. Section 5.4 gives some examples of when you would want to do this.
So in your example, the self parameter is modified and then destroyed. The caller's hello object is never modified. If you want to modify the caller's object, you need to take self by reference:
void func(this hello& self) {
self.data = 22;
}

Related

Is it safe to `std::move(*this)` into an object being created from `this->some_method`?

I am trying to build a chain of callable objects that can be later executed asynchronously. I wanted to try out the following approach: build a "nested" structure of nodes (by moving each node into its "parent") resulting in an object that stores all the computations and can be start the chain on demand.
This is what I had in mind:
template <typename TParent, typename TF>
struct node
{
TParent _parent;
TF _f;
node(TParent&& parent, TF&& f)
: _parent{std::move(parent)}, _f{std::move(f)}
{
}
template <typename TFContinuation>
auto then(TFContinuation&& f_continuation)
{
using this_type = node<TParent, TF>;
return node<this_type, std::decay_t<TFContinuation>>
{std::move(*this), std::move(f_continuation)};
// ^^^^^^^^^^^^^^^^
// ...safe?
}
};
The code above would allow the user to write chains like the following one:
int main()
{
node n{some_root_callable, []{/*...*/}};
n.then([]{/*...*/})
.then([]{/*...*/})
.then([]{/*...*/})
.then([]{/*...*/});
}
(The real implementation would support more useful abstraction such as when_all(...) or when_any(...).)
Wandbox example.
Assuming that TParent, TF, and TFContinuation are movable callable objects, is it safe (i.e. well-defined) to call std::move(*this) during the invocation of node::then?
You can do that and it's safe. It will only leaves members in an undefined but valid state in most cases. With that said, it is safe to move this, as long as you don't try to use its members again. But with standard library types and most user defined types, this won't even be a problem.
There is one thing that I would change. I would only allow call from rvalue this:
template <typename TFContinuation> // v-- notice the && here.
auto then(TFContinuation&& f_continuation) && {
using this_type = node<TParent, TF>;
return node<this_type, std::decay_t<TFContinuation>>{
std::move(*this), std::move(f_continuation)
};
}
The great this is you can even overload it when it's not an rvalue:
template <typename TFContinuation>
auto then(TFContinuation&& f_continuation) const & {
using this_type = node<TParent, TF>;
return node<this_type, std::decay_t<TFContinuation>>{
*this, std::move(f_continuation)
};
}
Whether there's a problem in that code depends on what that code does with the reference that it gets. If the called code turns the object into mush, then when it returns, your code has to deal with an object that's been turned into mush. But that's true of any function that you call from a member function, regardless of whether its called with an rvalue reference, a modifiable lvalue reference, a pointer, or any other mechanism you might want to imagine.

Is it possible to extract the capture list of a lambda?

From this link here I understand that inorder to pass a lambda we need to pass the method as a parameter and to store it in a std::function type. In such case, is it possible to extract the parameters from a capture list of a lambda?
example
struct foo
{
std::vector<int> t = {1,2,3};
};
void funct(std::function<void()> func)
{
func(); //This works fine . Can I extract the object foo from this lambda ?
}
int main()
{
foo a;
a.t.push_back(45);
funct( [a](){ std::cout << "New value is " << a.t[3] ; } );
}
In order to get access to the object stored in a std::function object, you must use the std::function::target<T> template function. In this case, T is the actual type of the object you passed to the function's constructor.
As it turns out, the type of a lambda is untype-able. That is, the standard requires that, whatever typename the compiler assigns it, it is a typename that you cannot enter on the keyboard. If you don't already have it (either directly or via type deduction on a value of that type), then there's nothing you can do to get it.
Now, you could do this:
template<typename T>
void funct(T func)
{
std::function<void()> stdfunc(func);
T *ptr_func = stdfunc.target<T>();
}
Of course, that's rather redundant, since you already have the lambda function's type.
However, even with the above code, you cannot access the capture variables of a lambda. Why? Because the standard doesn't say you can.
The short list of things you're allowed to do with lambda closures:
Copy/move construct them, assuming the types captured are copy/moveable.
Destroy them.
Call them with operator().
Convert them to a function pointer, but only if the lambda was capture-less (and non-generic).
The implementation is not required to allow you to access member variables of the lambda. And therefore, there is no standard way to do so. Even if the implementation made them public and named them the way they're named in your code (neither of which is required), the C++ standard does not guarantee that every implementation must do so.
I don't think you can. Because lambdas are equivalent to a class whose operator() has been overloaded. The captured parameters are actually private data members. In this example, your lambda equivalent to:
class _lambda {
public:
void operator()() const {
std::cout << "New value is " << a.t[3];
}
private:
foo a;
}
I don't think you can get access to a private member with friendship ungranted.

Using a class member as a default argument for a member function

Is there another way than manually overloading the corresponding member function and calling the first overload with the member as the argument?
I am trying something along the lines of
class test
{
string t1="test";
testfun( string& val = this->t1 )
{ /* modify val somehow */ }
};
(Test it: http://goo.gl/36p4CF)
Currently I guess there is no technical reason why this should not work.
Is there a solution doing it this way except overloading and setting the parameter manually?
Why is this not working, is there a technical reason for it?
[dcl.fct.default]/8:
The keyword this shall not be used in a default argument of a member function.
This is a special case of a general problem: You cannot refer to other parameters in a default argument of a parameter. I.e.
void f(int a, int b = a) {}
Is ill-formed. And so would be
class A
{
int j;
};
void f(A* this, int i = this->j) {}
Which is basically what the compiler transforms a member function of the form void f(int i = j) {} into. This originates from the fact that the order of evaluation of function arguments and the postfix-expression (which constitutes the object argument) is unspecified. [dcl.fct.default]/9:
Default arguments are evaluated each time the function is called.
The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in a default
argument, even if they are not evaluated.
Is there a solution doing it this way except overloading and setting the parameter manually?
No, you'd need an overload if you want a default argument to depend on another parameter, including this. Although, in this case, it doesn't make sense since this is a constructor, and t1 doesn't exist before it's called.
Why is this not working, is there a technical reason for it?
Because the evaluation order of function arguments isn't specified. To allow parameter values in default arguments, you'd need much more complex rules to ensure each parameter was initialised before being used.
You haven't said what you want to achieve. I assume that you need that each of your instances react on a specific way, depending on a certain class variable.
However, if you don't need a per-instance behaviour, then you can use static variables. The following works:
#include <iostream>
using namespace std;
struct test {
static string t1;
void say(const string &val=t1){
cout << val << "!" << endl;
}
};
string test::t1;
int main() {
cout << "Hello World" << endl;
test::t1 = string("asd");
test a;
a.say();
a.say("bla");
test::t1 = string("blahblah");
a.say();
return 0;
}
... which means that all the objects of the class test will use the static string t1 as their default value.
You can "hack" a little bit, and use this as an ugly sentinel:
void say(const string &val=t1){
if (&val == &t1) {
// They are using the default value, so act as you want
} else {
// they are providing a value
}
}

Syntax clarification

I was browsing some of Ubuntu's Mir examples and i stumbled upon code that i couldn't understand.
struct DemoServerConfiguration : mir::DefaultServerConfiguration
{
What is going on here ": mir::DefaultServerConfiguration"?
Inside that struct there's this
std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy()
{
return shell_placement_strategy(
[this]
{
return std::make_shared<me::FullscreenPlacementStrategy>(the_display());
});
}
Same story here, i don't understand the syntax the unclear parts are:
<msh::PlacementStrategy> the_shell_placement_strategy()
and
return shell_placement_strategy(
[this]
{
Inside the same struct again
std::initializer_list<std::shared_ptr<mi::EventFilter> const> the_event_filters() override
{
return filter_list;
}
Why the multiple <> <> <> nested? Why the the_event_filters() there?
And the last piece
mir::run_mir(config, [&config, &wm](mir::DisplayServer&)
{
code
});
Unclear part
(config, [&config, &wm](mir::DisplayServer&)
);
First example
That's simply a case of inheriting from an internal type:
class C
{
public:
class Internal
{
};
};
class D : public C::Internal
{
// D derives from Internal class, which is a member of C class
};
The :: is an operator of scope resolution. The expression A::B means: "B, which is a member of A". :: works for classes, structures and namespaces.
Second example
That's a little bit more complicated.
std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy()
{
return shell_placement_strategy(
[this]
{
return std::make_shared<me::FullscreenPlacementStrategy>(the_display());
});
}
Let's break it to parts.
std::shared_ptr<msh::PlacementStrategy> the_shell_placement_strategy()
This is a function / method the_shell_placement_strategy, which returns a result of type std::shared_ptr (generic class parametrized with msh::PlacementStrategy - see previous point).
return shell_placement_strategy(
It returns result of calling the shell_placement_strategy...
[this]
{
return std::make_shared<me::FullscreenPlacementStrategy>(the_display());
}
...which takes a lambda (nameless function) as a parameter. That nameless function wants to have access to this (thus [this]) and returns result of call to generic function std::make_shared, parametrized with me::FulscreenPlacementStrategy and called with parameter being a result of calling the_display() method / function.
You may read about lambdas elsewhere, but I'll include a short explanation for reference:
[access-specification](parameters){ body }
Where:
access-specification defines the relation between lambda and local variables. For example, [a] means, that lambda will have access to local variable a by value; [&a] - the same, but by reference; [&] - lambda will have access to all local variables by reference and so on.
parameters - regular definition of function parameters
body - regular body of lambda.
The lambda notation is a part of C++11 standard.
Last example
You now should be able to interpret this example:
mir::run_mir(config, [&config, &wm](mir::DisplayServer&)
{
code
});
Thats:
A call to run_mir method (or function), which is a part of mir class (or namespace);
With two parameters: config and a function, which accepts two parameters;
config is passed as first parameter;
A lambda is passed by the second parameter.
Now the lambda:
It wants to access by reference two local variables: config and wm
It accepts one parameter of type mir::DisplayServer& (there's no name for this parameter, so it seems, that it does not actually use it
It does <code> :)
First case, it is private inheritance. DemoServerConfiguration is derived from mir::DefaultServerConfiguration, where mir is probably a namespace (but could also be a class that declares the inner class DefaultServerConfiguration.
Second case, you are looking at lambda expression definition. You can read some introduction here.
Finally, the initializer lists are actually another feature introduced in C++11 standard (not yet supported by most of the compilers, AFAIK). Some introduction about them here.
mir::DefaultServerConfiguration
Here mir could be a namespace or a class inside which DefaultServerConfiguration is defined. So for example, it could be this:
namespace mir
{
class DefaultServerConfiguration
{
/*...*/
};
}
Or this,
class mir
{
public:
class DefaultServerConfiguration
{
/*...*/
};
}
In both cases, you could access the class DefaultServerConfiguration as:
mir::DefaultServerConfiguration
The same is true for other cases.
struct DemoServerConfiguration : mir::DefaultServerConfiguration
{
Here DemoServerConfiguration is a class deriving from mir::DefaultServerConfiguration. Make sense?
You also notice this in case of std::make_shared. Here std is a namespace defined by C++ Standard Library inside which the library defines make_shared function template.
Hope that helps.

What does operator()() define?

I'm sorry if this question gets reported but I can't seem to easily find a solution online. If I override operator()() what behavior does this define?
The operator() is the function call operator, i.e., you can use an object of the corresponding type as a function object. The second set of parenthesis contains the list of arguments (as usual) which is empty. For example:
struct foo {
int operator()() { return 17; };
};
int main() {
foo f;
return f(); // use object like a function
}
The above example just shows how the operator is declared and called. A realistic use would probably access member variables in the operator. Function object are used in many places in the standard C++ library as customization points. The advantage of using an object rather than a function pointer is that the function object can have data attached to it.