I've implemented a little helper wrapper for range-for loops that allows iterating over both keys and values of the associative Qt containers like QMap and QHash, extracting each pair as a structured binding, e.g.:
const QMap<int, QString> digitMap = { {1, "one"}, {2, "two"}, {3, "three"} };
for (auto [intKey, strVal] : make_keyval(digitMap)) {
qDebug() << intKey << "->" << strVal;
}
This isn't supported out-of-the-box for the Qt containers as they require using a specific pair of constKeyValueBegin() and constKeyValueEnd() methods (let's assume only non-mutating iterations). So my idea was to write a simple wrapper type that provides a pair of regular begin() and end() methods which simply call the keyValue ones on the container.
That's easy enough, but as a stretch goal I also wanted to make the wrapper usable with temporaries, like make_keyval(sometype.toMap()). The main challenge there was extending the lifetime of the temporary through the end of the iteration, as I'm going through a proxy object. Here's the solution I came up with:
template<typename C>
struct key_value_range_iterator {
key_value_range_iterator(const C& container) : m_rvalueContainer(nullptr), m_containerRef(container) {}
key_value_range_iterator(const C&& container) : m_rvalueContainer(std::make_unique<C>(std::move(container))), m_containerRef(*m_rvalueContainer) {}
typename C::const_key_value_iterator begin() const { return m_containerRef.constKeyValueBegin(); }
typename C::const_key_value_iterator end() const { return m_containerRef.constKeyValueEnd(); }
private:
const std::unique_ptr<C> m_rvalueContainer;
const C& m_containerRef;
};
template<typename C>
auto make_keyval(C&& container) { return key_value_range_iterator(std::forward<C>(container)); }
This seems to work fine for both regular variables and temporaries. For temporaries, m_rvalueContainer is used to store the moved temporary for the duration of the iteration, then it's referenced by m_containerRef. In the regular variable case, we just store the lvalue reference in m_containerRef directly leaving m_rvalueContainer unset. I verified the right constructor gets called in each case, and that the temporary only gets destroyed after the range-for loop completes.
So my question is simply: is this a correct implementation for my wrapper, or did I miss something? Or maybe there's a corner case I haven't thought of?
Note that in my initial version, I had m_rvalueContainer as a regular value, but I figured this would end up instantiating an empty container for nothing in the lvalue case (though that's a cheap operation for Qt containers), so I replaced it with unique_ptr to ensure there's no overhead in that case. Yes, it still ends up initializing it to nullptr, but that's neglectable.
Any other comments or recommendations?
Since make_keyval knows if the object passed in is lvalue or rvalue, you can pass that parameter on to your wrapper.
#include <type_traits>
template<typename C>
struct key_value_range_iterator {
key_value_range_iterator(const C container) : m_containerRef(container) {}
using iterator = typename std::remove_reference_t<C>::const_key_value_iterator;
iterator begin() const { return m_containerRef.constKeyValueBegin(); }
iterator end() const { return m_containerRef.constKeyValueEnd(); }
private:
const C m_containerRef;
};
template<typename C>
auto make_keyval(C&& container) { return key_value_range_iterator<C>(std::forward<C>(container)); }
When passing an lvalue C is deduces as QMap& making the wrapper hold a reference.
When passing an rvalue C is deduces as QMap making the wrapper move the rvalue into it's member.
Since C can be QMap& we need to use std::remove_reference to obtain the iterator type succesfully for the lvalue case.
Related
C++ containers do not hold const elements, e.g. you have const std::vector<int>, not std::vector<const int>.
This is a bit unfortunate when I am trying to adjust type of return value of a function based of if passed container was const or not.
Here is motivating example, please do not focus too much on algorithm or use of boost, I only use it since C++ optional has not support for references.
This code appears to work, but code looks quite ugly, so I wonder if concepts give us a way to write this in a nicer way.
I presume not since basically concepts are just predicates, but I am hoping for something nice, in particular return type is quite spammy.
template<typename C>
using match_const = std::conditional_t< std::is_const_v<std::remove_reference_t<C>>,
const typename std::remove_reference_t<C>::value_type,
typename std::remove_reference_t<C>::value_type>;
// no constraints
auto ofind(auto& container, const auto& value) -> boost::optional<match_const<decltype(container)>&> {
if (auto it = std::ranges::find(container, value); it!=container.end()){
return *it;
}
return boost::none;
}
// dummy concept
template<typename C>
concept Container = requires (C c){
{c.begin()};
{c.end()};
{c.size()} -> std::same_as<size_t>;
};
// constraints version
auto ofind2(Container auto& container, const auto& value) ->boost::optional<match_const<decltype(container)>&>{
if (auto it = std::ranges::find(container, value); it!=container.end()){
return *it;
}
return boost::none;
}
If my question is too vague here is my idealized version:
boost::optional<Container::real_reference> ofind(Container auto& container, const auto& value)
Where Container::real_reference is something that matches the constness unlike reference typedef in vector, for example consider this:
using CVI = const std::vector<int>;
static_assert(std::is_same_v<int&, CVI::reference>); // compiles
note: I know I should make second argument also more constrained, but for simplicity I left it as just const auto&.
Ranges already gives us a way to get the correct reference type of any range:
std::ranges::range_reference_t<R>
If R is vector<int>, that's int&. If R is vector<int> const, that's int const&. If R is span<int> const, that's... still int& because span is shallow-const (which is something your trait gets wrong, because it assumes that everything is deep-const).
This trait isn't magical, all it does is give you precisely the type that the underlying iterator dereferences to: decltype(*ranges::begin(r)).
With that, your find can look like:
template <range R>
auto ofind(R& container, const auto& value) -> boost::optional<range_reference_t<R>>;
Note that if you actually need to use the types of your parameters, using abbreviated function template syntax is not actually going to be all that abbreviated due to having to write decltype, so you can just... use normal function template syntax.
When using forwarding references, is it a bad idea to forward the
same value to more than one function? Consider the following piece of code:
template<typename Container>
constexpr auto
front(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).front(); }
template<typename Container>
constexpr auto
back(Container&& c)
-> typename Container::value_type
{ return std::forward<Container>(c).back(); }
template<typename Container>
constexpr auto
get_corner(Container&& c)
{
return do_something(front(std::forward<Container(c)),
back(std::forward<Container>(c));
}
If Container is an lvalue-reference, the function works just fine. However, I'm worrying about situations where rvalues are passed on to it, because the value would get invalidated once a move occurs. My doubt is: Is there a correct way to forward the container in that case, without losing the value category?
In general, it is not reasonable for the same function to forward the same parameter twice. Not unless it has specific knowledge of what the receiver of that forwarded parameter will do.
Remember: the behavior of std::forward can be equivalent to the behavior of std::move, depending on what parameter the user passed in. And the behavior of an xvalue will be contingent on how the receiving function processes it. If the receiver takes a non-const rvalue reference, it will likely move from that value if possible. That would leave you holding a moved-from object. If it takes a value, it will certainly move from it if the type supports it.
So unless you have specific knowledge of the expected behavior of the operations you are using, it is not safe to forward a parameter more than once.
There's actually no rvalue-reference version of std::begin - we just have (setting aside constexpr and return values):
template <class C>
??? begin(C& );
template <class C>
??? begin(C const& );
For lvalue containers, you get iterator, and for rvalue containers, you get const_iterator (or whatever the container-specific equivalent ends up being).
The one real problem in your code is returning decltype(auto). For lvalue containers, that's fine - you'll return a reference to an object whose lifetime exceeds the function. But for rvalue containers, that's returning a dangling reference. You'll want to return a reference for lvalue containers and a value for rvalue containers.
On top of that, forward-ing the containers into begin()/end() is probably not what you want to do. It'd be more efficient to conditionally wrap the result of the select() as a move iterator. Something like this answer of mine:
template <typename Container,
typename V = decltype(*std::begin(std::declval<Container&>())),
typename R = std::conditional_t<
std::is_lvalue_reference<Container>::value,
V,
std::remove_reference_t<V>
>
>
constexpr R operator()(Container&& c)
{
auto it = select(std::begin(c), std::end(c));
return *make_forward_iterator<Container>(it);
}
There's probably a less verbose way to express all of that.
You presumably realize that you wouldn't want to std::move an object being passed to multiple functions:
std::string s = "hello";
std::string hello1 = std::move(s);
std::string hello2 = std::move(s); // hello2 != "hello"
The role of forward is simply to restore any rvalue status that a parameter had when it was passed to the function.
We can quickly demonstrate that it is bad practice by forwarding one parameter two times to a function that has a move effect:
#include <iostream>
#include <string>
struct S {
std::string name_ = "defaulted";
S() = default;
S(const char* name) : name_(name) {}
S(S&& rhs) { std::swap(name_, rhs.name_); name_ += " moved"; }
};
void fn(S s)
{
std::cout << "fn(" << s.name_ << ")\n";
}
template<typename T>
void fwd_test(T&& t)
{
fn(std::forward<T>(t));
fn(std::forward<T>(t));
}
int main() {
fwd_test(S("source"));
}
http://ideone.com/NRM8Ph
If forwarding was safe, we should see fn(source moved) twice, but instead we see:
fn(source moved)
fn(defaulted moved)
In general, yes, this is potentially dangerous.
Forwarding a parameter ensures that if the value received by the universal reference parameter is an rvalue of some sort, it will continue to be an rvalue when it is forwarded. If the value is ultimately forwarded to a function (such as a move-constructor) that consumes the value by moving from it, its internal state is not likely to be valid for use in subsequent calls.
If you do not forward the parameter, it will not (in general) be eligible for move operations, so you would be safe from such behavior.
In your case, front and back (both the free functions and the member functions) do not perform a move on the container, so the specific example you gave should be safe. However, this also demonstrates that there's no reason to forward the container, since an rvalue won't be given different treatment from an lvalue--which is the only reason to preserve the distinction by forwarding the value in the first place.
I have simple data structure called array (similar to std::array). array class have method called all(). Here are method declarations:
const range<const_type_pointer> all() const;
range<type_point> all();
range is class template, which is constructed by two iterators. Here is simplified version of range class declaration:
template <typename Iterator>
class range {
typedef typename iterator_traits<Iterator>::type_value type_value;
typedef typename iterator_traits<Iterator>::type_reference type_reference;
typedef typename iterator_traits<Iterator>::type_pointer;
range(Iterator begin, Iterator end);
// methods & algorithms
// data members
mutable Iterator _begin;
mutable Iterator _end;
};
So basically, if I call method all on const array object, it should call const overload of method and return const range. Now, in my algorithms section, I have simple algorithm with following signature:
template <typename UnaryFunction>
range forEach(UnaryFunction function);
Then I tried following test:
void test1(const array<int, 10>& array)
{
auto r = array.all();
r.forEach([](int i) { std::cout << i << " "; });
}
And second one:
void test2(const array<int, 10>& array)
{
auto r = array.all();
r.forEach([](int& i) { ++i; });
}
In first case, where I was just printing variable i, compiler did not complained, even though I called non-const range method on const range object. In second case, compiler complained. Is this behaviour standard confornant?
As a compiler, I am using MSVS compiler.
First. Sice you are returning by value, it doesn't really make any difference if you are returning const range or range.
Second. auto r = array.all(); creates a copy of whatever was returned by all. Your r is a non-const object, and non-const forEach is used. But since the iterator is const in the second version, you can't modify the iterable.
auto works just like template argument deduction, which means that it drops top-level references and top-level const & volatile qualifiers. In other words, your r is of type range<const_pointer_type> in both cases.
Returning a const-qualified object should only be done in very special circumstances when you understand all details of its behaviour and really know that you want them.
Normally, you should just return objects without cv-qualifiers. It will play nicer with move semantics, and will not lead to incorrect expectations.
I have a struct, say
struct A {
A(int n) : n(n) {}
int n;
};
and I want to initialize a std::vector with some elements. I can do this by using an initialization list, or by emplacing the new elements:
// 1st version: 3 ctors, 3 copy ctors, 3 dtors
std::vector<A> v1{1, 2, 3};
// 2nd version: 3 ctors
std::vector<A> v2;
v2.reserve(3);
v2.emplace_back(4);
v2.emplace_back(5);
v2.emplace_back(6);
As the comments show, the first version calls 3 constructors, 3 copy constructors, and 3 destructors. The version with emplace only uses 3 constructors.
Question: Obviously the second version is better, but the first version is more succinct. Can I have the best of both worlds? Can I do a direct initialization without the extra cost?
(Here's a longer version of the A struct that shows what's happening.)
Since A is convertible from int, you can use the range constructor of vector:
auto inits = {1, 2, 3};
std::vector<A> v1{std::begin(inits), std::end(inits)};
Or in a single declaration-statement (assuming you can rely on RVO):
auto v1 = [inits={1, 2, 3}] { return std::vector<A>{std::begin(inits), std::end(inits)}; }();
Expanding on #ecatmur's answer, I've developed a piece of code that allows a very general solution for any type of vector and for any constructor calls. The constructor parameters for each element of the vector are stored in a tuple (of & or && as appropriate) which are then perfect-forwarded when the element is built. Each element is constructed only once, essentially equivalent to emplace_back. This forwarding would even allow a vector of move-only types to be built such as unique_ptr<?>.
(Update, due to RVO it should simply construct them in place. Unfortunately, however, the element type does require at least a copy-constructor or move-constructor to be visible, even if they are actually skipped by the optimizer. This means you can build a vector of unique_ptr, but not of mutex.)
auto v2 = make_vector_efficiently<A>(
pack_for_later(1) // 1-arg constructor of A
,pack_for_later(2,"two") // 2-arg constructor of A
,pack_for_later(3) // 1-arg constructor of A
);
The above code will create a vector<A> with three elements. In my example, A has two constructors, one which takes int,string as parameters.
pack_for_later builds a tuple that stores its parameters as &/&& references. That is then converted into on object (of type UniquePointerThatConverts, that has the desired conversion operator, in this case operator A().
Within make_vector_efficiently, an initializer list of these converter objects is built and then vector is constructed with the begin() and
end() of the initializer_list. You might expect that these iterators would be required to have type T* in order to construct a vector<T>, but it is sufficient that the type the iterator points to can convert to T.
The constructor then uses placement new to (copy-)construct from the converted object. But, thanks for RVO, the copy won't happen and the converter will be effectively doing the equivalent of emplace_back for us.
Anyway, any feedback appreciated. Finally, it's trivial to extend this to other containers besides vector.
Full code on Coliru Should work on any C++11 compiler.
Some more detailed notes, and copies of the important functions:
pack_for_later simply builds a std::tuple. The standard make_tuple isn't good enough as it ignores references. Each element of the tuple built by pack_for_later is a reference (& or && as appropriate, depending on whether the original parameter was an lvalue or rvalue)
template<typename ...T>
std:: tuple<T&&...> pack_for_later(T&&... args) {
// this function is really just a more
// 'honest' make_tuple - i.e. without any decay
return std:: tuple<T&&...> (std::forward<T>(args)...);
}
Next, make_vector_efficiently is the function that brings is all together. It's first parameter is the 'Target' type, the type of the elements in the vector we wish to create. The collection of tuples is converted into our special converter type UniquePointerThatConverts<Target> and the vector is constructed as discussed above.
template<typename Target, typename ...PackOfTuples>
auto make_vector_efficiently(PackOfTuples&&... args)
-> std::vector<Target>
{
auto inits = { UniquePointerThatConverts<Target>(std::forward<PackOfTuples>(args))...};
return std::vector<Target> {std::begin(inits), std::end(inits)};
}
Because A can have multiple constructors, and we want to be able to use any and all of them, pack_for_later can return many different types (don't forget about lvalues and rvalues too). But we need a single type to build the init list from. Therefore, we define a suitable interface:
template<typename Target>
struct ConvInterface {
virtual Target convert_to_target_type() const = 0;
virtual ~ConvInterface() {}
};
Each tuple is therefore converted to an object that implements this interface by make_Conv_from_tuple. It actually returns a unique_ptr to such an object which is then stored in a UniquePointerThatConverts that has the actual conversion operator. It is this type that is stored in the init list which is used to initialize the vector.
template<typename Target>
struct UniquePointerThatConverts {
std:: unique_ptr<ConvInterface<Target>> p; // A pointer to an object
// that implements the desired interface, i.e.
// something that can convert to the desired
// type (Target).
template<typename Tuple>
UniquePointerThatConverts(Tuple&& p_)
: p ( make_Conv_from_tuple<Target>(std:: move(p_)) )
{
//cout << __PRETTY_FUNCTION__ << endl;
}
operator Target () const {
return p->convert_to_target_type();
}
};
And, of course, the actual conversion operator which constructs from the pack.
template<typename Target, typename ...T>
struct Conv : public ConvInterface<Target> {
std::tuple<T...> the_pack_of_constructor_args;
Conv(std::tuple<T...> &&t) : the_pack_of_constructor_args(std:: move(t)) {}
Target convert_to_target_type () const override {
using idx = typename make_my_index_sequence<sizeof...(T)> :: type;
return foo(idx{});
}
template<size_t ...i>
Target foo(my_index_sequence<i...>) const {
// This next line is the main line, constructs
// something of the Target type (see the return
// type here) by expanding the tuple.
return {
std:: forward
< typename std:: tuple_element < i , std::tuple<T...> > :: type >
(std:: get<i>(the_pack_of_constructor_args))
...
};
}
};
I just read somebody call a class with a constructor and an operator() a predicate:
// Example
class Foo {
public:
Foo(Bar);
bool operator()(Baz);
private:
Bar bar;
};
However, I haven't heard the word predicate being used in this context before. I would call such a thing a functor. For me, a predicate would be something from the domain of formal logic.
This raises the following questions:
Is this a common word for something like Foo?
Are both terms used interchangeably, or do they mean slightly different things?
Or
Does the return type (bool versus something else) have something to do with it?
What about the operator() being const?
Functor is a term that refers to an entity that supports operator () in expressions (with zero or more parameters), i.e. something that syntactically behaves as a function. Functor is not necessarily an object of some class with overloaded operator (). Ordinary function names are functors as well. Although in some contexts you can see the term "functor" used in a more narrow and exclusive sense: just class objects, but not ordinary functions.
A predicate is a specific kind of functor: a functor that evaluates to a boolean value. It is not necessarily a value of bool type, but rather a value of any type with "boolean" semantics. The type should be implicitly convertible to bool though.
The shown class is a functor that implements a predicate.
A predicate is a boolean function.
About the operator() being non-const here: it should ideally be const, yes.
A predicate is a special kind of function object. See this excellent column by Nicolai Josuttis. To quote:
A function object that returns a Boolean value is a predicate. That's
what almost all tutorials, books, and manuals write about predicates
of the STL. This, however, is not the whole story.
However, there is an additional requirement that is unfortunately not
mentioned in any manual or in the C++ Standard: A predicate should
always return the same result for the same value.
Or, in the language of C++: You should declare operator() as a
constant member function (and not play games with mutable or casts).
For the same reason, a copy of a predicate should have the same state
as the original.
The reason is that the STL algorithms will copy function objects around, and the copying should not affect the outcome of applying the function objects.
template<typename Arg0>
struct UnaryPredicate
:
public std::function<bool(Arg0 const&)>
{
bool operator()(Arg0 const& a0) const
{
return // your code here
}
};
template<typename Arg0, typename Arg1>
struct BinaryPredicate
:
public std::function<bool(Arg0 const&, Arg1 const&)>
{
bool operator()(Arg const& a0, Arg const& a1) const
{
return // your code here
}
};
As has been said, a predicate is just a user supplied directive to analyze something to a boolean state. So you can have the same two things doing the same thing...
struct is_odd
{
is_odd() : count(0);
bool operartor () (int i) const { ++count; return (i % 2) == 1; }
private
int count;
}
And...
bool isOdd(int i) { return (i % 2) == 1; }
So, what is so special about the functor? It maintains state if you want it to! That means that while these two lines of code do the same thing (assume v is a vector, with values 0 - 9)...
for_each(v.begin(), v.end(), isOdd); //using C-style function pointer
And...
is_odd fn = for_each(v.begin(), v.end(), is_odd); //using functor
Only with the second use case can you then call...
int calls = fn.count;
That is because for_each (as well as other STL algorithm functions) returns the functor it used at the end, so now the final state can be queried.
One other cool thing to note is that in the second case, we are using what is called an "anonymous" object.
From the MSDN:
Represents the method that defines a set of criteria and determines
whether the specified object meets those criteria.
http://msdn.microsoft.com/en-us/library/bfcke1bz.aspx