Possible 'this' implementation in C++ - c++

I found this post when i try to understand what xvalue, glvalue and prvalue values are.
I also intuitively think that, under the hood, this is passed to member function like :
void SomeClass::func(SomeClass* this, int a, int b)
but as stated in the answer and the standard, this should be prvalue so my assumption was wrong.
I tried to mimic this as prvalue
template<typename T>
T* possible_this_impl() {
T* ref { nullptr };
// Somehow retrieve the currently referred object
return ref;
}
struct foo {
int a_non_static_member_function() {
possible_this_impl<foo>(); // Now it is a prvalue
possible_this_impl<foo>()->x;
possible_this_impl<foo>()->y;
}
public:
int x {};
int y {};
};
int main()
{
foo f;
f.a_non_static_member_function();
}
But actually, I wonder what could be possible implementation of this ? Could anyone enlighten me ?
Note: No need very deep explanation but maybe a simple explanation could be enough.

Related

Defining uninitilized reference c++

I have a template
T template<typename T>undefined_behavior(void)
{
throw;
return T{};
}
template<typename T>
struct UBHandler
{
const bool valid;
T value;
(operator T)()
{if(valid)return value;return undefined_behavior<T>();}
};
This works when using rvalues but breaks when using rvalue references because—references aren't pointers and can't be constructed out of thin air.
error: member ‘... ::value’ is uninitialized reference
Before I wipe out all code relying on this and start over, is there a way to satisfy the compiler with some kind of null reference or magic uncorn—union thing?
Or something.
Undefined behavior welcome.
This should work because std::optional exists and std::optional has rvalue reverence overloads? sadness. Perhaps not, after reading previously asked questions. But it was proposed in 2014 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3982.html I have no idea how to interpret this into a solution.
What is std::optional doing to get away with this that I'm missing? Sadness.
I tried reading the following questions but I have no ideas.
Constraint on std::optional's forwarding reference constructor
std::optional specialization for reference types
Why GCC rejects std::optional for references?
Will std::experimental::optional<> support references?
std::optional<T> call by reference
Seems trivial to overload the type for references and write:
#include <stdexcept>
template<typename T>
struct UBHandler
{
const bool valid;
T value;
operator T() {
if (valid) return value;
throw std::runtime_error("");
}
};
template<typename T>
struct UBHandler<T&>
{
T *const value;
UBHandler() : value(nullptr) {}
UBHandler(T& value) : value(&value) {}
operator T() {
if (value) return *value;
throw std::runtime_error("");
}
};
int main() {
UBHandler<int&> a;
a + 1;
int b = 1;
int &c = b;
UBHandler<int&> d{c};
d + 1;
}

Use of rvalue references in function parameter of overloaded function creates too many combinations

Imagine you have a number of overloaded methods that (before C++11) looked like this:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
};
This function makes a copy of a (MyBigType), so I want to add an optimization by providing a version of f that moves a instead of copying it.
My problem is that now the number of f overloads will duplicate:
class MyClass {
public:
void f(const MyBigType& a, int id);
void f(const MyBigType& a, string name);
void f(const MyBigType& a, int b, int c, int d);
// ...
void f(MyBigType&& a, int id);
void f(MyBigType&& a, string name);
void f(MyBigType&& a, int b, int c, int d);
// ...
};
If I had more parameters that could be moved, it would be unpractical to provide all the overloads.
Has anyone dealt with this issue? Is there a good solution/pattern to solve this problem?
Thanks!
Herb Sutter talks about something similar in a cppcon talk
This can be done but probably shouldn't. You can get the effect out using universal references and templates, but you want to constrain the type to MyBigType and things that are implicitly convertible to MyBigType. With some tmp tricks, you can do this:
class MyClass {
public:
template <typename T>
typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type
f(T&& a, int id);
};
The only template parameter will match against the actual type of the parameter, the enable_if return type disallows incompatible types. I'll take it apart piece by piece
std::is_convertible<T, MyBigType>::value
This compile time expression will evaluate to true if T can be converted implicitly to a MyBigType. For example, if MyBigType were a std::string and T were a char* the expression would be true, but if T were an int it would be false.
typename std::enable_if<..., void>::type // where the ... is the above
this expression will result in void in the case that the is_convertible expression is true. When it's false, the expression will be malformed, so the template will be thrown out.
Inside the body of the function you'll need to use perfect forwarding, if you are planning on copy assigning or move assigning, the body would be something like
{
this->a_ = std::forward<T>(a);
}
Here's a coliru live example with a using MyBigType = std::string. As Herb says, this function can't be virtual and must be implemented in the header. The error messages you get from calling with a wrong type will be pretty rough compared to the non-templated overloads.
Thanks to Barry's comment for this suggestion, to reduce repetition, it's probably a good idea to create a template alias for the SFINAE mechanism. If you declare in your class
template <typename T>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value, void>::type;
then you could reduce the declarations to
template <typename T>
EnableIfIsMyBigType<T>
f(T&& a, int id);
However, this assumes all of your overloads have a void return type. If the return type differs you could use a two-argument alias instead
template <typename T, typename R>
using EnableIfIsMyBigType = typename std::enable_if<std::is_convertible<T, MyBigType>::value,R>::type;
Then declare with the return type specified
template <typename T>
EnableIfIsMyBigType<T, void> // void is the return type
f(T&& a, int id);
The slightly slower option is to take the argument by value. If you do
class MyClass {
public:
void f(MyBigType a, int id) {
this->a_ = std::move(a); // move assignment
}
};
In the case where f is passed an lvalue, it will copy construct a from its argument, then move assign it into this->a_. In the case that f is passed an rvalue, it will move construct a from the argument and then move assign. A live example of this behavior is here. Note that I use -fno-elide-constructors, without that flag, the rvalue cases elides the move construction and only the move assignment takes place.
If the object is expensive to move (std::array for example) this approach will be noticeably slower than the super-optimized first version. Also, consider watching this part of Herb's talk that Chris Drew links to in the comments to understand when it could be slower than using references. If you have a copy of Effective Modern C++ by Scott Meyers, he discusses the ups and downs in item 41.
You may do something like the following.
class MyClass {
public:
void f(MyBigType a, int id) { this->a = std::move(a); /*...*/ }
void f(MyBigType a, string name);
void f(MyBigType a, int b, int c, int d);
// ...
};
You just have an extra move (which may be optimized).
My first thought is that you should change the parameters to pass by value. This covers the existing need to copy, except the copy happens at the call point rather than explicitly in the function. It also allows the parameters to be created by move construction in a move-able context (either unnamed temporaries or by using std::move).
Why you would do that
These extra overloads only make sense, if modifying the function paramers in the implementation of the function really gives you a signigicant performance gain (or some kind of guarantee). This is hardly ever the case except for the case of constructors or assignment operators. Therefore, I would advise you to rethink, whether putting these overloads there is really necessary.
If the implementations are almost identical...
From my experience this modification is simply passing the parameter to another function wrapped in std::move() and the rest of the function is identical to the const & version. In that case you might turn your function into a template of this kind:
template <typename T> void f(T && a, int id);
Then in the function implementation you just replace the std::move(a) operation with std::forward<T>(a) and it should work. You can constrain the parameter type T with std::enable_if, if you like.
In the const ref case: Don't create a temporary, just to to modify it
If in the case of constant references you create a copy of your parameter and then continue the same way the move version works, then you may as well just pass the parameter by value and use the same implementation you used for the move version.
void f( MyBigData a, int id );
This will usually give you the same performance in both cases and you only need one overload and implementation. Lots of plusses!
Significantly different implementations
In case the two implementations differ significantly, there is no generic solution as far as I know. And I believe there can be none. This is also the only case, where doing this really makes sense, if profiling the performance shows you adequate improvements.
You might introduce a mutable object:
#include <memory>
#include <type_traits>
// Mutable
// =======
template <typename T>
class Mutable
{
public:
Mutable(const T& value) : m_ptr(new(m_storage) T(value)) {}
Mutable(T& value) : m_ptr(&value) {}
Mutable(T&& value) : m_ptr(new(m_storage) T(std::move(value))) {}
~Mutable() {
auto storage = reinterpret_cast<T*>(m_storage);
if(m_ptr == storage)
m_ptr->~T();
}
Mutable(const Mutable&) = delete;
Mutable& operator = (const Mutable&) = delete;
const T* operator -> () const { return m_ptr; }
T* operator -> () { return m_ptr; }
const T& operator * () const { return *m_ptr; }
T& operator * () { return *m_ptr; }
private:
T* m_ptr;
char m_storage[sizeof(T)];
};
// Usage
// =====
#include <iostream>
struct X
{
int value = 0;
X() { std::cout << "default\n"; }
X(const X&) { std::cout << "copy\n"; }
X(X&&) { std::cout << "move\n"; }
X& operator = (const X&) { std::cout << "assign copy\n"; return *this; }
X& operator = (X&&) { std::cout << "assign move\n"; return *this; }
~X() { std::cout << "destruct " << value << "\n"; }
};
X make_x() { return X(); }
void fn(Mutable<X>&& x) {
x->value = 1;
}
int main()
{
const X x0;
std::cout << "0:\n";
fn(x0);
std::cout << "1:\n";
X x1;
fn(x1);
std::cout << "2:\n";
fn(make_x());
std::cout << "End\n";
}
This is the critical part of the question:
This function makes a copy of a (MyBigType),
Unfortunately, it is a little ambiguous. We would like to know what is the ultimate target of the data in the parameter. Is it:
1) to be assigned to an object that existing before f was called?
2) or instead, stored in a local variable:
i.e:
void f(??? a, int id) {
this->x = ??? a ???;
...
}
or
void f(??? a, int id) {
MyBigType a_copy = ??? a ???;
...
}
Sometimes, the first version (the assignment) can be done without any copies or moves. If this->x is already long string, and if a is short, then it can efficiently reuse the existing capacity. No copy-construction, and no moves. In short, sometimes assignment can be faster because we can skip the copy contruction.
Anyway, here goes:
template<typename T>
void f(T&& a, int id) {
this->x = std::forward<T>(a); // is assigning
MyBigType local = std::forward<T>(a); // if move/copy constructing
}
If the move version will provide any optimization then the implementation of the move overloaded function and the copy one must be really different. I don't see a way to get around this without providing implementations for both.

How does this example in standard section 6.8 works?

In standard Section §6.8 of the Standard (N3690 draft) I see this weird piece of code :
struct T2 { T2(int){ } };
int a, (*(*b)(T2))(int), c, d;
What is int(*(*b)(T2))(int) ?!
Is b a pointer to T2's constructor ?! or maybe a pointer to function pointer ?
It's weird that the bellow code also compile fine !:
struct T2 { T2(int){ } };
int((*b)(T2));
int (*(*b)(T2))(int)
It declares b as pointer to a function which:
takes T2 as argument
and returns pointer to a function which
takes an int as argument
and returns an int.
One should simplify this declaration using typedefs as:
typedef int (*return_type) (int);
typedef return_type(*function_type) (T2);
Or better use C++11 style type aliases:
using return_type = int(*)(int);
using function_type = return_type(*)(T2);
Then the declaration becomes this:
function_type b; //so simple!
Hope that helps.
It is declaration of variable b. b is a pointer to function with one parameter of type T2. The return type of this function is pointer to function with one parameter int returning int.
This should help you understand what is going on here:
struct T2 { T2(int){ } };
typedef int (*func)(int);
int
(*foo(T2))(int) {
}
func
bar(T2) {
}
int main() {
int (*(*b)(T2))(int);
b = &foo;
b = &bar;
return 0;
}
So this is a function that take a T2 and return a function pointer to a function that return an int and take an int as parameter.
I a add this to my example of why c(++) is an horrible language.
By the way, you cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")

Is there a way to detect construction of a const qualified object? [duplicate]

This question already has answers here:
Can an object know its own constness?
(7 answers)
Closed 8 years ago.
Assuming two declarations:
const type x; // case a
type y; // case b
is it possible to detect case "a" or "b" in type's constructor so that I can execute different operations?
From the standard §12.1/3 we have that:
A constructor can be invoked for a const, volatile or const volatile object. const and volatile semantics (7.1.6.1) are not applied on an object under construction. They come into effect when the constructor for the most derived object (1.8) ends.
therefore this behaves like expected by never being const-qualified at construction (otherwise how could you edit member objects in the body?). So, it seems it's not possible to use type traits on this.
A use case for this would be the following: assuming you are working with an underlying C API that describe specific objects (in a much wider sense), taking hints on their future use along the lines of:
STATIC = will not be modified
DYNAMIC = can be modified
one could create a wrapper around those C objects and give a STATIC hint on a const construction, and a DYNAMIC hint on a non const construction. Of course const_cast exists and could mess things up, but I'm assuming sane coding here :P.
Am I missing something (considering also C++11 and C++14)?
I dont really know if its worth the struggle and this solution is for sure not perfect as we have to use a helper class Object<T>, but atleast it works very similiar to your requested behaviour:
#include <iostream>
#include <type_traits>
template<typename T>
using Object = typename std::conditional<std::is_const<T>::value, typename T::const_type, typename T::type>::type;
template<bool IsConst>
struct FooHelper;
struct Foo
{
typedef FooHelper<false> type;
typedef const FooHelper<true> const_type;
protected:
Foo(bool isConst)
{
if (isConst)
std::cout << "const" << std::endl;
else
std::cout << "non-const" << std::endl;
}
};
template<>
struct FooHelper<false> : public Foo
{
FooHelper() : Foo(false) {}
};
template<>
struct FooHelper<true> : public Foo
{
FooHelper() : Foo(true) {}
};
int main()
{
Object<Foo> obj;
Object<const Foo> cobj;
}

Aggregate initialization with curly braces

In C++11, are the aggregates allowed to be copied with curly-braces syntax? I have the following code:
struct s
{
int x;
};
template<class T>
struct holder
{
template<class A>
holder(A&& x) : t{x} {}
T t;
};
Each one of the statements below works.
auto s1 = s{1};
auto s2(s1);
auto s3{s1}; ///NOTE : this works!
However, the second statement below raises the error cannot convert 's' to 'int' in initialization.
holder<s> h{5};
holder<s> h1{s{5}};
I am using gcc 4.8.2. Why do I get this error?
In C++11, when a type T is an aggregate type, initialisation using { ... } performs aggregate initialisation. Aggregate initialisation always initialises the members of T, not T itself.
Although this is exactly what the standard requires, this is unwanted, which is why in a future standard, the rule will likely be changed to make a special exception for initialisation from the same type. This is core language issue 1467.
Until that time, unfortunately, the error you are getting is entirely correct, and you will have to work around it.
First of all this code
struct s
{
int x;
};
template<class T>
struct holder
{
template<class A>
holder(A&& x) : t{x} {}
T t;
};
int main()
{
holder<s> h{5};
return 0;
}
is compiled successfuly.
The invalid statement is
holder<s> h1{s{5}};
The problem is that in fact you are trying to execute
s s1 = { s{5} };
However the compiler is unable to convert an object of type s to an object of type int (that to initialize s1.x) when it tries to make assignment
s.x = s{5};