I have a function like (please don't care about returning temporary by reference. This is just an example to explain the problem),
const foo<const int>& get_const()
{
foo<int> f;
return f;
}
This obviously won't compile. I am looking for a way to ensure callers won't change the T of foo. How can I ensure that?
I have seen the similar behavior for boost::shared_ptr. shared_ptr<T> is convertible to const shared_ptr<const T>. I couldn't figure out how it is doing this.
Any help would be great.
The compiler sees foo<T> and foo<const T> as two completely different and unrelated types, so the foo class needs to support this explicitly just as with any other conversion. If you have control over the foo class, you need to provide a copy constructor or an implicit conversion operator (or both).
template<typename T>
class foo
{
public:
// Regular constructor
foo(T t) : t(t) {}
// Copy constructor (works for any type S convertable to T, in particular S = non-const T if T is const)
// Remember that foo<T> and foo<S> are unrelated, so the accessor method must be used here
template<typename S> foo (const foo<S>& copy) : t(copy.getT()) {}
// Accessor
T getT() const { return t; }
// Conversion operator
operator foo<const T> () const { return foo<const T>(t); }
private:
T t;
};
Assuming that Foo is defined something like this:
template<typename T> class Foo
{
public:
Foo(const T& value) : m_value(value) { }
const T& getValue() const { return m_value; }
void setValue(const T& value) { m_value = value; }
private:
T m_value;
};
Then, in order to ensure that clients of Foo do not modify m_value (I assume that this is what is meant by "I am looking for a way to ensure callers won't change the T of foo"), you need to const-qualify the Foo object rather than its template parameter, i.e.
Foo<int> x(1);
x.setValue(2); // OK
const Foo<int> y(1);
y.setValue(2); // does not compile
Therefore, your get_foo function should return a const Foo<T>&, not a const Foo<const T>&.
Here's a complete, compilable example:
#include <iostream>
template<typename T> class Foo
{
public:
Foo(const T& value) : m_value(value) { }
const T& getValue() const { return m_value; }
void setValue(const T& value) { m_value = value; }
private:
T m_value;
};
template<class T> class Owner
{
public:
Owner(const T& value) : m_foo(value) { }
Foo<T>& getFoo() { return m_foo; }
const Foo<T>& getConstFoo() const { return m_foo; }
private:
Foo<T> m_foo;
};
int main(int argc, char** argv)
{
Owner<int> x(1);
x.getFoo().setValue(2);
// x.getConstFoo().setValue(3); // will not compile
}
If I'm not mistaken, the boost::shared_ptr implementation has a non-explicit constructor that takes a const T& reference as an argument and then uses a const_cast on the RHS's pointer to remove the const, allowing implicit conversions between them.
Something like this:
shared_ptr(const shared_ptr<const T>& r) : ptr(const_cast<T*>(r.ptr)) {}
Is that what you're looking for?
First of all, you're returning a local object by reference...that's not good.
foo and foo are two different types so you'll have to write code (conversion constructors) to explicitly convert them.
To get what you wanted, consider this:
template <typename T>
struct foo {T* t;};
const foo<int>& get_const(const foo<int>& f) {
return f;
}
foo<int> f;
const foo<int>& cf = get_const(f);
f.t = 0; // ok, f is not const
*cf.t = 0; // ok because cf.t is const but what cf.t points to is not
cf.t = 0; // compiler error cf.t is const and cannot be lvalue
foo<int>& cf = get_const(f); // compiler error, cannot convert non-const to const without const_cast
If you done your encapsulation correctly and only access members with const getter and non-const setters, this should be good enough for you. Remember if people really want to change your object, they can always const_cast. Const-correctness is only to catch unintentional mistakes.
Related
I have a struct made of templated types that work with incomplete types unless instantiated, like std::vector. Access into those types work with typesafe index wrappers. Example:
template<class T>
struct Idx{unsinged val;};
struct Holder{
MyVector<Foo> foos;
MyVector<Bar> bars;
};
const Foo& foo = holder.foos.get(Idx<Foo>(...));
This works well: Idx does not need to know the type of the template param because it is never used. Holder works with forward declarations of Foo/Bar too. I cannot confuse Idx<Foo> with Idx<Bar> because I can only get the respective type with them. Because this is so unique I though of adding convenience functions to holder:
struct Holder{
MyVector<Foo> foos;
MyVector<Bar> bars;
const Foo& get(Idx<Foo> idx) { return foos.get(idx);}
const Bar& get(Idx<Bar> idx) { return bars.get(idx);}
};
But now I need full types for Holder, which I wanted to avoid. Is it possible to use incomplete types AND the convenience functions? Maybe some templates help but I'd need some dispatch to either foos or bars which most likely instantiates it.
Maybe you can create a template function
template<typename T>
const T& getByIndex(const MyVector<T>& vec, const Idx<T>& idx)
{ return vec.get(idx); }
Then you can use it inside Holder like
const Foo& get(const Idx<Foo>& idx) { return getByIndex(foos, idx); }
Do not expect the parameter as instance Idx<Foo> because this would require the fully defined type (the reference allows incomplete types).
I found a solution during the discussion of then answer by #grek40 :
I need a templatized get function so the containers get function does not get instantiated in the header. Hence we have:
template<class T> const T& get(DescIdx<T> idx) const { return getContainer<T>().get(idx); }
Now we need a getContainer function which is simple: template<class T> const MyVector<T>& getContainer() const;
This needs to be instantiated for our containers like: template<> inline const MyVector<Foo>& Holder::getContainer() const { return foos; }
So all in all:
template<class T>
struct Idx{unsinged val;};
struct Holder{
MyVector<Foo> foos;
MyVector<Bar> bars;
template<class T> const T& get(DescIdx<T> idx) const { return getContainer<T>().get(idx); }
template<class T> const MyVector<T>& getContainer() const;
};
template<> inline const MyVector<Foo>& Holder::getContainer() const { return foos; }
template<> inline const MyVector<Bar>& Holder::getContainer() const { return bars; }
// Somewhere else
const Foo& foo = holder.get(Idx<Foo>(...));
This might be improved by using template metaprogramming. Steps:
Define a boost::mpl::list of all types (Foo, Bar)
Create a templatized struct MetaHolder that holds 1 MyVector<T>
Let Holder inherit from MetaHolder instantiated with each type
Implement 1(!) generic getContainer functions which simply returns MetaHolder<T>.container.
Everything will get resolved at compile time, so no runtime overhead. Not sure about compile time overhead though as Boost.MPL can get quite heavy.
I guess not, but I would like to confirm. Is there any use for const Foo&&, where Foo is a class type?
They are occasionally useful. The draft C++0x itself uses them in a few places, for example:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The above two overloads ensure that the other ref(T&) and cref(const T&) functions do not bind to rvalues (which would otherwise be possible).
Update
I've just checked the official standard N3290, which unfortunately isn't publicly available, and it has in 20.8 Function objects [function.objects]/p2:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Then I checked the most recent post-C++11 draft, which is publicly available, N3485, and in 20.8 Function objects [function.objects]/p2 it still says:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The semantics of getting a const rvalue reference (and not for =delete) is for saying:
we do not support the operation for lvalues!
even though, we still copy, because we can't move the passed resource, or because there is no actual meaning for "moving" it.
The following use case could have been IMHO a good use case for rvalue reference to const, though the language decided not to take this approach (see original SO post).
The case: smart pointers constructor from raw pointer
It would usually be advisable to use make_unique and make_shared, but both unique_ptr and shared_ptr can be constructed from a raw pointer. Both constructors get the pointer by value and copy it. Both allow (i.e. in the sense of: do not prevent) a continuance usage of the original pointer passed to them in the constructor.
The following code compiles and results with double free:
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
Both unique_ptr and shared_ptr could prevent the above if their relevant constructors would expect to get the raw pointer as a const rvalue, e.g. for unique_ptr:
unique_ptr(T* const&& p) : ptr{p} {}
In which case the double free code above would not compile, but the following would:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Note that ptr could still be used after it was moved, so the potential bug is not totally gone. But if user is required to call std::move such a bug would fall into the common rule of: do not use a resource that was moved.
One can ask: OK, but why T* const&& p?
The reason is simple, to allow creation of unique_ptr from const pointer. Remember that const rvalue reference is more generic than just rvalue reference as it accepts both const and non-const. So we can allow the following:
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
this wouldn't go if we would expect just rvalue reference (compilation error: cannot bind const rvalue to rvalue).
Anyhow, this is too late to propose such a thing. But this idea does present a reasonable usage of an rvalue reference to const.
They are allowed and even functions ranked based on const, but since you can't move from const object referred by const Foo&&, they aren't useful.
Besides std::ref, the standard library also uses const rvalue reference in std::as_const for the same purpose.
template <class T>
void as_const(const T&&) = delete;
It is also used as return value in std::optional when getting the wrapped value:
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
As well as in std::get:
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
This is presumably in order to maintain the value category as well as constness of the wrapper when accessing the wrapped value.
This makes a difference whether const rvalue ref-qualified functions can be called on the wrapped object. That said, I don't know any uses for const rvalue ref qualified functions.
I can't think of a situation where this would be useful directly, but it might be used indirectly:
template<class T>
void f(T const &x) {
cout << "lvalue";
}
template<class T>
void f(T &&x) {
cout << "rvalue";
}
template<class T>
void g(T &x) {
f(T());
}
template<class T>
void h(T const &x) {
g(x);
}
The T in g is T const, so f's x is an T const&&.
It is likely this results in a comile error in f (when it tries to move or use the object), but f could take an rvalue-ref so that it cannot be called on lvalues, without modifying the rvalue (as in the too simple example above).
Perhaps it could be considered useful in this context (coliru link):
#include <iostream>
// Just a simple class
class A {
public:
explicit A(const int a) : a_(a) {}
int a() const { return a_; }
private:
int a_;
};
// Returning a const value - shouldn't really do this
const A makeA(const int a) {
return A{a};
}
// A wrapper class referencing A
class B {
public:
explicit B(const A& a) : a_(a) {}
explicit B(A&& a) = delete;
// Deleting the const&& prevents this mistake from compiling
//explicit B(const A&& a) = delete;
int a() const { return a_.a(); }
private:
const A& a_;
};
int main()
{
// This is a mistake since makeA returns a temporary that B
// attempts to reference.
auto b = B{makeA(3)};
std::cout << b.a();
}
It prevents the mistake being compiled. There are clearly a bunch of other problems with this code that compiler warnings do pick up, but perhaps the const&& helps?
Rvalue references are meant to allow moving data.
So in the vast majority of case its use is pointless.
The main edge case you will find it is to prevent people to call a function with an rvalue:
template<class T>
void fun(const T&& a) = delete;
The const version will cover all the edge cases, contrary to the non const version.
Here is why, consider this example:
struct My_object {
int a;
};
template<class T>
void fun(const T& param) {
std::cout << "const My_object& param == " << param.a << std::endl;
}
template<class T>
void fun( T& param) {
std::cout << "My_object& param == " << param.a << std::endl;
}
int main() {
My_object obj = {42};
fun( obj );
// output: My_object& param == 42
const My_object const_obj = {64};
fun( const_obj );
// output: const My_object& param == 64
fun( My_object{66} );
// const My_object& param == 66
return 0;
}
Now if you'd like to prevent someone using fun( My_object{66} ); since in the present case, it will be converted to const My_object&, you need to define:
template<class T>
void fun(T&& a) = delete;
And now fun( My_object{66} ); will throw an error, however, if some smarty pants programmer decides to write:
fun<const My_object&>( My_object{1024} );
// const My_object& param == 1024
This will work again and call the const lvalue overload version of that function... Fortunately we can put an end to such profanity adding const to our deleted overload:
template<class T>
void fun(const T&& a) = delete;
It's somewhat disturbing how pretty much everyone in this thread (with the exception of #FredNurk and #lorro) misunderstand how const works, so allow me to chime in.
Const reference only forbids modifying the immediate contents of the class. Not only do we have static and mutable members which we very well can modify through a const reference; but we also can modify the contents of the class stored in a memory location referenced by a non-static, non-mutable pointer - as long as we don't modify the pointer itself.
Which is exactly the case of an extremely common Pimpl idiom. Consider:
// MyClass.h
class MyClass
{
public:
MyClass();
MyClass(int g_meat);
MyClass(const MyClass &&other); // const rvalue reference!
~MyClass();
int GetMeat() const;
private:
class Pimpl;
Pimpl *impl {};
};
// MyClass.cpp
class MyClass::Pimpl
{
public:
int meat {42};
};
MyClass::MyClass() : impl {new Pimpl} { }
MyClass::MyClass(int g_meat) : MyClass()
{
impl->meat = g_meat;
}
MyClass::MyClass(const MyClass &&other) : MyClass()
{
impl->meat = other.impl->meat;
other.impl->meat = 0;
}
MyClass::~MyClass()
{
delete impl;
}
int MyClass::GetMeat() const
{
return impl->meat;
}
// main.cpp
const MyClass a {100500};
MyClass b (std::move(a)); // moving from const!
std::cout << a.GetMeat() << "\n"; // returns 0, b/c a is moved-from
std::cout << b.GetMeat() << "\n"; // returns 100500
Behold - a fully functional, const-correct move constructor which accepts const rvalue references.
I guess not, but I would like to confirm. Is there any use for const Foo&&, where Foo is a class type?
They are occasionally useful. The draft C++0x itself uses them in a few places, for example:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The above two overloads ensure that the other ref(T&) and cref(const T&) functions do not bind to rvalues (which would otherwise be possible).
Update
I've just checked the official standard N3290, which unfortunately isn't publicly available, and it has in 20.8 Function objects [function.objects]/p2:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Then I checked the most recent post-C++11 draft, which is publicly available, N3485, and in 20.8 Function objects [function.objects]/p2 it still says:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The semantics of getting a const rvalue reference (and not for =delete) is for saying:
we do not support the operation for lvalues!
even though, we still copy, because we can't move the passed resource, or because there is no actual meaning for "moving" it.
The following use case could have been IMHO a good use case for rvalue reference to const, though the language decided not to take this approach (see original SO post).
The case: smart pointers constructor from raw pointer
It would usually be advisable to use make_unique and make_shared, but both unique_ptr and shared_ptr can be constructed from a raw pointer. Both constructors get the pointer by value and copy it. Both allow (i.e. in the sense of: do not prevent) a continuance usage of the original pointer passed to them in the constructor.
The following code compiles and results with double free:
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
Both unique_ptr and shared_ptr could prevent the above if their relevant constructors would expect to get the raw pointer as a const rvalue, e.g. for unique_ptr:
unique_ptr(T* const&& p) : ptr{p} {}
In which case the double free code above would not compile, but the following would:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Note that ptr could still be used after it was moved, so the potential bug is not totally gone. But if user is required to call std::move such a bug would fall into the common rule of: do not use a resource that was moved.
One can ask: OK, but why T* const&& p?
The reason is simple, to allow creation of unique_ptr from const pointer. Remember that const rvalue reference is more generic than just rvalue reference as it accepts both const and non-const. So we can allow the following:
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
this wouldn't go if we would expect just rvalue reference (compilation error: cannot bind const rvalue to rvalue).
Anyhow, this is too late to propose such a thing. But this idea does present a reasonable usage of an rvalue reference to const.
They are allowed and even functions ranked based on const, but since you can't move from const object referred by const Foo&&, they aren't useful.
Besides std::ref, the standard library also uses const rvalue reference in std::as_const for the same purpose.
template <class T>
void as_const(const T&&) = delete;
It is also used as return value in std::optional when getting the wrapped value:
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
As well as in std::get:
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
This is presumably in order to maintain the value category as well as constness of the wrapper when accessing the wrapped value.
This makes a difference whether const rvalue ref-qualified functions can be called on the wrapped object. That said, I don't know any uses for const rvalue ref qualified functions.
I can't think of a situation where this would be useful directly, but it might be used indirectly:
template<class T>
void f(T const &x) {
cout << "lvalue";
}
template<class T>
void f(T &&x) {
cout << "rvalue";
}
template<class T>
void g(T &x) {
f(T());
}
template<class T>
void h(T const &x) {
g(x);
}
The T in g is T const, so f's x is an T const&&.
It is likely this results in a comile error in f (when it tries to move or use the object), but f could take an rvalue-ref so that it cannot be called on lvalues, without modifying the rvalue (as in the too simple example above).
Perhaps it could be considered useful in this context (coliru link):
#include <iostream>
// Just a simple class
class A {
public:
explicit A(const int a) : a_(a) {}
int a() const { return a_; }
private:
int a_;
};
// Returning a const value - shouldn't really do this
const A makeA(const int a) {
return A{a};
}
// A wrapper class referencing A
class B {
public:
explicit B(const A& a) : a_(a) {}
explicit B(A&& a) = delete;
// Deleting the const&& prevents this mistake from compiling
//explicit B(const A&& a) = delete;
int a() const { return a_.a(); }
private:
const A& a_;
};
int main()
{
// This is a mistake since makeA returns a temporary that B
// attempts to reference.
auto b = B{makeA(3)};
std::cout << b.a();
}
It prevents the mistake being compiled. There are clearly a bunch of other problems with this code that compiler warnings do pick up, but perhaps the const&& helps?
Rvalue references are meant to allow moving data.
So in the vast majority of case its use is pointless.
The main edge case you will find it is to prevent people to call a function with an rvalue:
template<class T>
void fun(const T&& a) = delete;
The const version will cover all the edge cases, contrary to the non const version.
Here is why, consider this example:
struct My_object {
int a;
};
template<class T>
void fun(const T& param) {
std::cout << "const My_object& param == " << param.a << std::endl;
}
template<class T>
void fun( T& param) {
std::cout << "My_object& param == " << param.a << std::endl;
}
int main() {
My_object obj = {42};
fun( obj );
// output: My_object& param == 42
const My_object const_obj = {64};
fun( const_obj );
// output: const My_object& param == 64
fun( My_object{66} );
// const My_object& param == 66
return 0;
}
Now if you'd like to prevent someone using fun( My_object{66} ); since in the present case, it will be converted to const My_object&, you need to define:
template<class T>
void fun(T&& a) = delete;
And now fun( My_object{66} ); will throw an error, however, if some smarty pants programmer decides to write:
fun<const My_object&>( My_object{1024} );
// const My_object& param == 1024
This will work again and call the const lvalue overload version of that function... Fortunately we can put an end to such profanity adding const to our deleted overload:
template<class T>
void fun(const T&& a) = delete;
It's somewhat disturbing how pretty much everyone in this thread (with the exception of #FredNurk and #lorro) misunderstand how const works, so allow me to chime in.
Const reference only forbids modifying the immediate contents of the class. Not only do we have static and mutable members which we very well can modify through a const reference; but we also can modify the contents of the class stored in a memory location referenced by a non-static, non-mutable pointer - as long as we don't modify the pointer itself.
Which is exactly the case of an extremely common Pimpl idiom. Consider:
// MyClass.h
class MyClass
{
public:
MyClass();
MyClass(int g_meat);
MyClass(const MyClass &&other); // const rvalue reference!
~MyClass();
int GetMeat() const;
private:
class Pimpl;
Pimpl *impl {};
};
// MyClass.cpp
class MyClass::Pimpl
{
public:
int meat {42};
};
MyClass::MyClass() : impl {new Pimpl} { }
MyClass::MyClass(int g_meat) : MyClass()
{
impl->meat = g_meat;
}
MyClass::MyClass(const MyClass &&other) : MyClass()
{
impl->meat = other.impl->meat;
other.impl->meat = 0;
}
MyClass::~MyClass()
{
delete impl;
}
int MyClass::GetMeat() const
{
return impl->meat;
}
// main.cpp
const MyClass a {100500};
MyClass b (std::move(a)); // moving from const!
std::cout << a.GetMeat() << "\n"; // returns 0, b/c a is moved-from
std::cout << b.GetMeat() << "\n"; // returns 100500
Behold - a fully functional, const-correct move constructor which accepts const rvalue references.
I'm porting FastDelegate to C++0x using variadic templates.
#include "FastDelegate.h"
template<class R=fastdelegate::detail::DefaultVoid, class ...P>
class fast_delegate_base {
private:
typedef typename fastdelegate::detail::DefaultVoidToVoid<R>::type desired_ret_t;
typedef desired_ret_t (*static_func_ptr)(P...);
typedef R (*unvoid_static_func_ptr)(P...);
typedef R (fastdelegate::detail::GenericClass::*generic_mem_fn)(P...);
typedef fastdelegate::detail::ClosurePtr<generic_mem_fn, static_func_ptr, unvoid_static_func_ptr> closure_t;
closure_t closure_;
public:
// Typedefs to aid generic programming
typedef fast_delegate_base type;
// Construction and comparison functions
fast_delegate_base() { clear(); }
fast_delegate_base(const fast_delegate_base &x)
{
closure_.CopyFrom(this, x.closure_);
}
void operator = (const fast_delegate_base &x)
{
closure_.CopyFrom(this, x.closure_);
}
bool operator ==(const fast_delegate_base &x) const
{
return closure_.IsEqual(x.closure_);
}
bool operator !=(const fast_delegate_base &x) const
{
return !closure_.IsEqual(x.closure_);
}
bool operator <(const fast_delegate_base &x) const
{
return closure_.IsLess(x.closure_);
}
bool operator >(const fast_delegate_base &x) const
{
return x.closure_.IsLess(closure_);
}
// Binding to non-const member functions
template<class X, class Y>
fast_delegate_base(Y *pthis, desired_ret_t (X::* function_to_bind)(P...) )
{
closure_.bindmemfunc(fastdelegate::detail::implicit_cast<X*>(pthis), function_to_bind);
}
template<class X, class Y>
inline void bind(Y *pthis, desired_ret_t (X::* function_to_bind)(P...))
{
closure_.bindmemfunc(fastdelegate::detail::implicit_cast<X*>(pthis), function_to_bind);
}
// Binding to const member functions.
template<class X, class Y>
fast_delegate_base(const Y *pthis, desired_ret_t (X::* function_to_bind)(P...) const)
{
closure_.bindconstmemfunc(fastdelegate::detail::implicit_cast<const X*>(pthis), function_to_bind);
}
template<class X, class Y>
inline void bind(const Y *pthis, desired_ret_t (X::* function_to_bind)(P...) const)
{
closure_.bindconstmemfunc(fastdelegate::detail::implicit_cast<const X *>(pthis), function_to_bind);
}
// Static functions. We convert them into a member function call.
// This constructor also provides implicit conversion
fast_delegate_base(desired_ret_t (*function_to_bind)(P...) )
{
bind(function_to_bind);
}
// for efficiency, prevent creation of a temporary
void operator = (desired_ret_t (*function_to_bind)(P...) )
{
bind(function_to_bind);
}
inline void bind(desired_ret_t (*function_to_bind)(P...))
{
closure_.bindstaticfunc(this, &fast_delegate_base::invoke_static_func, function_to_bind);
}
// Invoke the delegate
template<typename ...A>
R operator()(A&&... args) const
{
return (closure_.GetClosureThis()->*(closure_.GetClosureMemPtr()))(std::forward<A>(args)...);
}
// Implicit conversion to "bool" using the safe_bool idiom
private:
typedef struct safe_bool_struct
{
int a_data_pointer_to_this_is_0_on_buggy_compilers;
static_func_ptr m_nonzero;
} useless_typedef;
typedef static_func_ptr safe_bool_struct::*unspecified_bool_type;
public:
operator unspecified_bool_type() const { return empty()? 0: &safe_bool_struct::m_nonzero; }
// necessary to allow ==0 to work despite the safe_bool idiom
inline bool operator==(static_func_ptr funcptr) { return closure_.IsEqualToStaticFuncPtr(funcptr); }
inline bool operator!=(static_func_ptr funcptr) { return !closure_.IsEqualToStaticFuncPtr(funcptr); }
// Is it bound to anything?
inline bool operator ! () const { return !closure_; }
inline bool empty() const { return !closure_; }
void clear() { closure_.clear();}
// Conversion to and from the DelegateMemento storage class
const fastdelegate::DelegateMemento & GetMemento() { return closure_; }
void SetMemento(const fastdelegate::DelegateMemento &any) { closure_.CopyFrom(this, any); }
private:
// Invoker for static functions
R invoke_static_func(P... args) const
{
return (*(closure_.GetStaticFunction()))(args...);
}
};
// fast_delegate<> is similar to std::function, but it has comparison operators.
template<typename _Signature>
class fast_delegate;
template<typename R, typename ...P>
class fast_delegate<R(P...)> : public fast_delegate_base<R, P...>
{
public:
typedef fast_delegate_base<R, P...> BaseType;
fast_delegate() : BaseType() { }
template<class X, class Y>
fast_delegate(Y * pthis, R (X::* function_to_bind)(P...))
: BaseType(pthis, function_to_bind)
{ }
template<class X, class Y>
fast_delegate(const Y *pthis, R (X::* function_to_bind)(P...) const)
: BaseType(pthis, function_to_bind)
{ }
fast_delegate(R (*function_to_bind)(P...))
: BaseType(function_to_bind)
{ }
void operator = (const BaseType &x)
{
*static_cast<BaseType*>(this) = x;
}
};
But, one of the limitations of my implementation is, when using non-member functions, and in case that function accepts parameter(s) by value, an extra value copy for each parameters take place. I assume that this occurs between fast_delegate_base::operator()() and fast_delegate_base::invoke_static_func().
I tried to make fast_delegate_base::invoke_static_func() to accept Rvalue parameters, but failed.
For example:
class C1
{
public:
C1() { printf("C1()\n"); }
~C1() { printf("~C1()\n"); }
C1(const C1&)
{
printf("C1(const C1&)\n");
}
int test(int t) const
{
printf("C1::test(%d)\n", t);
return 1;
}
};
int test(C1 c)
{
c.test(1234);
return 1;
}
// ...
C1 c1;
fast_delegate<int(C1)> t1(test);
t1(c1);
Result of this code is:
C1()
C1(const C1&)
C1(const C1&)
C1::test(1234)
~C1()
~C1()
~C1()
Do you have any idea to avoid this extra value copy?
It looks to me like this copy is inherent in the design of the class, specifically the existence of invoke_static_func.
From what I can see, this is a proxy to normalize static functions and member functions into just member functions, so they every dispatch can be done as a member function call. The only difference is that the member is the fast_delegate_base instance rather than an instance of whatever class the target function is a member of.
So there's an extra call frame when calling static functions, and to get rid of that extra copy you would need to make the extra call frame (invoke_static_func) take its parameter by a reference (ignore for now the consequences of this if the argument type is not a value).
Unfortunately, invoke_static_func needs to be called via a function pointer which has an argument list containing value types, so operator() is forced to make a copy in order to invoke the function pointer (i.e. to invoke invoke_static_func). Making invoke_static_func take parameters by reference doesn't help, because it still has to be invoked via a function pointer that does not have reference argument types.
And there's no way invoke_static_func can avoid making a copy to call test(C1), that's just a simple call by value - so you need both copies to make this design work.
To explain it from a different perspective, thin of it in terms of pure C:
Operator() needs to call a function func (this_ptr, arg_1, arg_2, arg_3). The target function will expect these parameters to be in particular registers or particular stack locations depending on their position in the argument list and size.
But a static function does not have the magic first 'this' parameter, its signature is just func(arg_1, arg_2, arg_3). So it expects all the other arguments to be in different registers and/or stack locations than the corresponding member function does. So you need that copy to move the arguments into the right registers/stack locations to comply with the calling convention for the static function.
Which basically, means you can't avoid that second copy for a static function with this design.
However... you may be able to improve on this by some crafty template metaprogramming to apply std::move to value type arguments in the implementation of invoke_static_func, reducing your call overhead to a copy and a move, which is almost as good as just one copy.
I'll update this answer if and when I figure whether that's possible (and if so how).
Edit
Something like this should do the trick:
template <bool IsClass, class U>
struct move_if_class
{
template <typename T>
T&& operator()(const T& t) { return std::move(const_cast<T&>(t)); }
};
template <class T>
struct move_if_class<false,T>
{
T&& operator()(typename std::remove_reference<T>::type& t) { return std::forward<T>(t); }
T&& operator()(typename std::remove_reference<T>::type&& t) { return std::forward<T>(t); }
};
R invoke_static_func(P... args) const
{
return (*(closure_.GetStaticFunction()))(move_if_class<std::is_class<P>::value,P>()(args)...);
}
And after adding a move c'tor:
C1()
C1(const C1&)
C1(C1&&)
C1::test(1234)
~C1()
~C1()
~C1()
I guess not, but I would like to confirm. Is there any use for const Foo&&, where Foo is a class type?
They are occasionally useful. The draft C++0x itself uses them in a few places, for example:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The above two overloads ensure that the other ref(T&) and cref(const T&) functions do not bind to rvalues (which would otherwise be possible).
Update
I've just checked the official standard N3290, which unfortunately isn't publicly available, and it has in 20.8 Function objects [function.objects]/p2:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Then I checked the most recent post-C++11 draft, which is publicly available, N3485, and in 20.8 Function objects [function.objects]/p2 it still says:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
The semantics of getting a const rvalue reference (and not for =delete) is for saying:
we do not support the operation for lvalues!
even though, we still copy, because we can't move the passed resource, or because there is no actual meaning for "moving" it.
The following use case could have been IMHO a good use case for rvalue reference to const, though the language decided not to take this approach (see original SO post).
The case: smart pointers constructor from raw pointer
It would usually be advisable to use make_unique and make_shared, but both unique_ptr and shared_ptr can be constructed from a raw pointer. Both constructors get the pointer by value and copy it. Both allow (i.e. in the sense of: do not prevent) a continuance usage of the original pointer passed to them in the constructor.
The following code compiles and results with double free:
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
Both unique_ptr and shared_ptr could prevent the above if their relevant constructors would expect to get the raw pointer as a const rvalue, e.g. for unique_ptr:
unique_ptr(T* const&& p) : ptr{p} {}
In which case the double free code above would not compile, but the following would:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Note that ptr could still be used after it was moved, so the potential bug is not totally gone. But if user is required to call std::move such a bug would fall into the common rule of: do not use a resource that was moved.
One can ask: OK, but why T* const&& p?
The reason is simple, to allow creation of unique_ptr from const pointer. Remember that const rvalue reference is more generic than just rvalue reference as it accepts both const and non-const. So we can allow the following:
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
this wouldn't go if we would expect just rvalue reference (compilation error: cannot bind const rvalue to rvalue).
Anyhow, this is too late to propose such a thing. But this idea does present a reasonable usage of an rvalue reference to const.
They are allowed and even functions ranked based on const, but since you can't move from const object referred by const Foo&&, they aren't useful.
Besides std::ref, the standard library also uses const rvalue reference in std::as_const for the same purpose.
template <class T>
void as_const(const T&&) = delete;
It is also used as return value in std::optional when getting the wrapped value:
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
As well as in std::get:
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
This is presumably in order to maintain the value category as well as constness of the wrapper when accessing the wrapped value.
This makes a difference whether const rvalue ref-qualified functions can be called on the wrapped object. That said, I don't know any uses for const rvalue ref qualified functions.
I can't think of a situation where this would be useful directly, but it might be used indirectly:
template<class T>
void f(T const &x) {
cout << "lvalue";
}
template<class T>
void f(T &&x) {
cout << "rvalue";
}
template<class T>
void g(T &x) {
f(T());
}
template<class T>
void h(T const &x) {
g(x);
}
The T in g is T const, so f's x is an T const&&.
It is likely this results in a comile error in f (when it tries to move or use the object), but f could take an rvalue-ref so that it cannot be called on lvalues, without modifying the rvalue (as in the too simple example above).
Perhaps it could be considered useful in this context (coliru link):
#include <iostream>
// Just a simple class
class A {
public:
explicit A(const int a) : a_(a) {}
int a() const { return a_; }
private:
int a_;
};
// Returning a const value - shouldn't really do this
const A makeA(const int a) {
return A{a};
}
// A wrapper class referencing A
class B {
public:
explicit B(const A& a) : a_(a) {}
explicit B(A&& a) = delete;
// Deleting the const&& prevents this mistake from compiling
//explicit B(const A&& a) = delete;
int a() const { return a_.a(); }
private:
const A& a_;
};
int main()
{
// This is a mistake since makeA returns a temporary that B
// attempts to reference.
auto b = B{makeA(3)};
std::cout << b.a();
}
It prevents the mistake being compiled. There are clearly a bunch of other problems with this code that compiler warnings do pick up, but perhaps the const&& helps?
Rvalue references are meant to allow moving data.
So in the vast majority of case its use is pointless.
The main edge case you will find it is to prevent people to call a function with an rvalue:
template<class T>
void fun(const T&& a) = delete;
The const version will cover all the edge cases, contrary to the non const version.
Here is why, consider this example:
struct My_object {
int a;
};
template<class T>
void fun(const T& param) {
std::cout << "const My_object& param == " << param.a << std::endl;
}
template<class T>
void fun( T& param) {
std::cout << "My_object& param == " << param.a << std::endl;
}
int main() {
My_object obj = {42};
fun( obj );
// output: My_object& param == 42
const My_object const_obj = {64};
fun( const_obj );
// output: const My_object& param == 64
fun( My_object{66} );
// const My_object& param == 66
return 0;
}
Now if you'd like to prevent someone using fun( My_object{66} ); since in the present case, it will be converted to const My_object&, you need to define:
template<class T>
void fun(T&& a) = delete;
And now fun( My_object{66} ); will throw an error, however, if some smarty pants programmer decides to write:
fun<const My_object&>( My_object{1024} );
// const My_object& param == 1024
This will work again and call the const lvalue overload version of that function... Fortunately we can put an end to such profanity adding const to our deleted overload:
template<class T>
void fun(const T&& a) = delete;
It's somewhat disturbing how pretty much everyone in this thread (with the exception of #FredNurk and #lorro) misunderstand how const works, so allow me to chime in.
Const reference only forbids modifying the immediate contents of the class. Not only do we have static and mutable members which we very well can modify through a const reference; but we also can modify the contents of the class stored in a memory location referenced by a non-static, non-mutable pointer - as long as we don't modify the pointer itself.
Which is exactly the case of an extremely common Pimpl idiom. Consider:
// MyClass.h
class MyClass
{
public:
MyClass();
MyClass(int g_meat);
MyClass(const MyClass &&other); // const rvalue reference!
~MyClass();
int GetMeat() const;
private:
class Pimpl;
Pimpl *impl {};
};
// MyClass.cpp
class MyClass::Pimpl
{
public:
int meat {42};
};
MyClass::MyClass() : impl {new Pimpl} { }
MyClass::MyClass(int g_meat) : MyClass()
{
impl->meat = g_meat;
}
MyClass::MyClass(const MyClass &&other) : MyClass()
{
impl->meat = other.impl->meat;
other.impl->meat = 0;
}
MyClass::~MyClass()
{
delete impl;
}
int MyClass::GetMeat() const
{
return impl->meat;
}
// main.cpp
const MyClass a {100500};
MyClass b (std::move(a)); // moving from const!
std::cout << a.GetMeat() << "\n"; // returns 0, b/c a is moved-from
std::cout << b.GetMeat() << "\n"; // returns 100500
Behold - a fully functional, const-correct move constructor which accepts const rvalue references.