C++11 provides the std::allocator_traits class as the standard way to use allocators. The static function std::allocator_traits::construct() takes a pointer to where the object should be constructed. The std::allocator_traits::allocate() static function, however, returns an allocator::pointer value, which only has to behave like a pointer but it is not necessarily one (in general, although std::allocator::pointer is required to be a pointer).
How is one supposed to use the allocation and construction static methods if, in general, they will work with incompatible types? Can they be used only if the pointer type is actually convertible to a normal plain pointer?
There are two techniques to do this depending on what you have at the moment.
If you have an lvalue expression, say the value field in a node, then you can use std::addressof like so:
allocator_traits<allocator_type>::construct(alloc, std::addressof(ptr->value), ...);
where ptr is an allocator_type::pointer.
However if you don't have a field to dereference and you want to convert an allocator_type::pointer to T*, there's a trick you need to implement first:
template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
return p;
}
template <class Pointer>
inline
typename std::pointer_traits<Pointer>::element_type*
to_raw_pointer(Pointer p) noexcept
{
return p != nullptr ? ::to_raw_pointer(p.operator->())
: nullptr;
}
And now you can say:
allocator_traits<allocator_type>::construct(alloc, to_raw_pointer(ptr), ...);
Starting with C++20, there is std::to_address, proposed in P0653.
Related
I have this class:
template<typename T, size_t N>
class Array {
private:
T array[N];
public:
template <typename... InitValues>
constexpr Array(InitValues... init_values)
: array{ init_values... } {}
[[nodiscard]]
consteval int len() const noexcept { return sizeof(array) / sizeof(T); }
}
I would like to know, for such a simple member function, when I should provide the necessary ref-qualified overloads.
With the actual code, I can compile and run the following code:
constexpr collections::Array a = collections::Array<long, 5>{1L, 2L, 3L};
SECTION("length of the array") {
REQUIRE( a.len() == 5 );
REQUIRE( collections::Array<int, 1>{1}.len() == 1 );
}
1- Why I can compile the second REQUIRE that contains the call with the rvalue?
Now I am gonna change the len() member function to this:
[[nodiscard]]
consteval int len() const& noexcept { return sizeof(array) / sizeof(T); }
2- Why I can compile both with the const&? I suppose that they are two are different ref-qualified usages. I assume that I can make the call with the first one, which is an lvalue, but can't understand why I can compile the second having defined the len() method as const&.
Last change:
[[nodiscard]]
consteval int len() const&& noexcept { return sizeof(array) / sizeof(T); }
And finally, I got a compiler error on a.get<I>().
'this' argument to member function 'len' is an lvalue, but function has rvalue ref-qualifier
REQUIRE( a.len() == 5 );
that works perfect if I comment that line of code and I just run:
REQUIRE( collections::Array<int, 1>{1}.len() == 1 );
and also I could use std::move(a) to perform the cast of a to an rvalue reference and make the code compile. But I don't want to do that.
What is the correct way of code those examples in terms of ref-qualified overloads?
Don't forget about the questions on the examples above
EDIT:
I will add another member function that could potentially do different things based on the ref-qualified implementation (or that what I am suppose that could happen):
template <size_t I>
requires concepts::AccessInBounds<I, N>
constexpr T get() const noexcept {
return array[I];
}
template <size_t I>
requires concepts::AccessInBounds<I, N>
constexpr T& get() const& noexcept {
return array[I];
}
To question 1: why not? The rule is the same as for lvalues: you can call const member functions regardless of the constness of the object.
To question 2: Because it is meant to be identical to having a const& function parameter: the function can be called with any lvalue or rvalue. It exists primarily to allow you to distinguish between lvalue and rvalue overloads:
class Array {
// These two declarations would be ambiguous for Array rvalues
// int len() const;
// int len() &&;
// These are not: your test expressions will use different overloads
int len() const&;
int len() &&;
};
The two functions in your edit are also ambiguous, for both lvalues and rvalues. A motivating example would be more along these lines: suppose my class provides functionality to some resource that could be expensive to copy, but is cheaper to move, say a std::vector.
template<class T>
class VectorView {
std::vector<T> vector;
public:
// ...
constexpr std::vector<T> const& base() const noexcept { return vector; }
};
Now there is no way for a user of this class to transfer ownership of the vector data back from a view object, even if that would be useful when calling the base() function on an rvalue. Because it is in the spirit of C++ to avoid paying for things you do not need, you could allow this by adding an rvalue-qualified overload that instead returns an rvalue reference using std::move.
So the answer to whether you need this kind of overload is it depends, which is unfortunately also in the spirit of C++. If you were implementing something like my example class for the standard library, then you certainly would, because it is based on std::ranges::owning_view. As you can see on that page, it covers all four possible base()s. If you were instead only using a reference to a source range, it would be unexpected and inappropriate to move from that object, so the related ref_view only has a const base() function like the one I wrote.
Edit As for move semantics, the difference between something like an array and a vector is that Array<T,N> is based on T[N], while std::vector<T> is based on T*. Moving the array requires N move operations (linear time complexity), and whether a move is an improvement over a copy depends on T. Also, it needs memory space for 2N elements. On the other hand, a vector only ever needs three pointers to do its job, so it can be moved in constant time, while copying still takes linear time.
This potential gain is the rationale for move semantics and rvalue references in a nutshell. The ability to also have &&-qualified member functions completes this language feature, but is not as significant as move constructors and assignment functions. I also found the answers to this question useful, as they give some more examples of ref-qualified overloads.
Before I ask what I want to know, here's a little background:
I'm wrapping a std::function in my own class Function, which stores some additional data along with the std::function object. Later on, I have a std::vector<Function<Signature>> that stores a whole bunch of Function's of the same signature (e.g. void(int)). These std::function's may represent normal free functions, functors, or member functions that have been bound to an object using std::bind.
At some later point, I want to traverse the std::vector, and check some properties of the Function objects. For example, I want to select every Function that is bound to a particular member-function (regardless of the object it will be called on). This means I have to find a way to store these member-function pointers, while discarding their exact type. In other words, I need to be able to store a pointer of type void (A::*)() and another pointer of type void (B::*)() in the same field.
I used to do this using a union to 'cast' the member-function-pointer to a void*, but then found out that member-function-pointers are implementation-defined and don't have the same size as pointers. Now I'm looking for a portable solution, and this is what I came up with:
class MemFunPtr
{
friend bool operator==(MemFunPtr const &lhs, MemFunPtr const &rhs);
enum { SIZE = sizeof(void(MemFunPtr::*)()) };
char buf[SIZE];
public:
template <typename T, typename R, typename ... Args>
MemFunPtr(R (T::*ptr)(Args ...))
{
union
{
R (T::*memfcn_)(Args ...);
char buf_[SIZE];
} caster;
caster.memfcn_ = ptr;
memcpy(buf, caster.buf_, SIZE);
}
};
bool operator==(MemFunPtr const &lhs, MemFunPtr const &rhs)
{
return memcmp(lhs.buf, rhs.buf, MemFunPtr::SIZE) == 0;
}
Now my question is, if this is portable. I would be even more happy with a more straightforward way of doing this. I looked in to std::mem_fn, but it seems that the type of these objects is unspecified (the examples on cppreference.com use auto), so I don't think this is where the solution lies.
For example, I have such a smart pointer:
template <typename T>
class SmartPointer
{
public:
....
T* operator & () { return m_p; }
private:
T* m_p;
}
void foo()
{
std::vector<SmartPointer<int> >vec;
vec.push_back(....);
vec.resize(.....);
......
}
Is this usage safe? I try it in MINGW4.4, It work ok....
In fact, those code is use work for COM, when I wanted to get a object, I need to do these
SmpartPointer<COMObj> spObj;
HRESULT hr = xxxxx->QueryInterface(&spObj);
then i wanted to store the pointer in a vector, so
std::vector<SmpartPointer<COMObj> >vec;
.....
In C++03, there is no explicit requirement that value types in containers do not overload unary operator&; however per 23.1p3 the objects stored are required to model CopyConstructible (20.1.3p1, Table 30). This in turn requires that the expression &t should yield a value of type T * that denotes the address of t. So overloaded unary operator& is permissible, but only if it has the "correct" return type and returns the correct value.
Your operator& is invalid; it should return SmartPointer<T> *.
In C++11 this was relaxed (through the use of std::addressof) so unary operator& can have any type and return any value.
In all versions of the standard, the type parameter of complex and valarray must not overload unary operator&; this is to allow them to be treated as contiguous storage.
If you want to bind a reference to a function f, you can use std::bind(f, std::ref(x)). In this case f takes a reference or makes a copy.
Now I have a function void g(T & t). I would like to bind the input argument to std::shared_ptr<T> mySharedPtr like this: std::bind(g, mySharedPtr). This would guarantee that mySharedPtr's data would have a lifetime at least as long as the bind. But since g takes a reference, this does not type-check.
Is there something similar to std::ref that takes a std::shared_ptr and dereferences it before passing it into g? If not, could I make one myself?
(If you give an answer using lambdas, please also include one without lambdas since my compiler does not support them.)
Edit: std::bind(g, std::ref(*mySharedPtr)) does not work since it loses the lifetime guarantee of the std::shared_ptr.
It seems you could create a deref() function which would create an object dereferencing something looking like a pointer upon conversion:
template <typename P>
class pointer_wrapper {
P ptr;
public:
pointer_wrapper(P p): ptr(p) {}
operator decltype(*std::declval<P>())&() {
return *ptr;
}
};
template <typename P>
pointer_wrapper<P> deref(P p) {
return p;
}
It may be better to make the conversion a member template to allow a few more conversions.
Suppose I have a class X:
class X {
// ...
size_t hash() const { return ...; }
};
I would like to create a std::tr1::unordered_map<X, int, HashFn> where I want to pass in
X::hash() as HashFn. I know I can declare my own functor object. I feel that
there should be a way to do this by directly passing a pointer to X::hash().
Is there?
No; as you've shown it, you need a small utility struct:
#include <functional>
template<typename T, std::size_t (T::*HashFunc)() const = &T::hash>
struct hasher : std::unary_function<T, std::size_t>
{
std::size_t operator ()(T const& t) const
{
return (t.*HashFunc)();
}
};
Then you can create an unordered_map like so:
std::tr1::unordered_map<X, int, hasher<X> > m;
No, there isn't. The reason is that whatever is used as your HashFn must take a single argument which is a const reference to an object in the container. X::hash takes a single argument which is a const pointer to an object in the container (the this pointer is an implicit first argument in this case), so using that function by it self is not possible.
You probably use some bind magic, using boost::lambda and boost::bind. I'm not exactly sure how, but it would probably look something like this:
boost::bind(&X::hash, &_1);
Which creates a function object which will call X::hash with a pointer.
size_t hash() const { return ...;}
A function which calculates hash value takes one parameter of type Key which your function doesn't take. Hence its signature is wrong to begin with.
Since you want to implement a function, rather than a functor, here is how it should be done:
size_t hash(const KeyType &key)
{
return /*calculate hash and return it*/;
}
Make it static member function and pass it as X::hash or make it a free function, is your choice.
You can't directly, but you can wrap it. The easy way to do so is to use boost::mem_fn(), or the standard equivalents if your compiler supports them: tr1::mem_fn() (from TR1) or std::mem_fn() (from C++11).
EDIT: Actually it's not so simple. mem_fn() will work fine for a function parameter, but since its return type is unspecified it's difficult to use as a template parameter. If you have C++11 support you could use decltype to find the type; otherwise you're probably best off writing your own function object as you mentioned.