How can I take ownership of a collection using range-v3? - c++

I want to return a range from a function that represents a view on a STL collection, something like this:
auto createRange() {
std::unordered_set<int> is = {1, 2, 3, 4, 5, 6};
return is | view::transform([](auto&& i) {
return i;
});
}
However, view::transform does not take ownership of is, so when I run this, there is undefined behavior, because is is freed when createRange exits.
int main(int argc, char* argv[]) {
auto rng = createRange();
ranges::for_each(rng, [](auto&& i) {
std::cout << std::to_string(i) << std::endl;
});
}
If I try std::move(is) as the input, I get a static assert indicating that I can't use rvalue references as inputs to a view. Is there any way to ensure that the view takes ownership of the collection?
Edit: Some Additional Info
I want to add some clarifying info. I have a stream of data, data that I have a view on that transforms the data into a struct, Foo, that looks something like this:
struct Foo {
std::string name;
std::unordered_set<int> values;
}
// Take the input stream and turn it into a range of Foos
auto foos = data | asFoo();
What I want to do is create a range of std::pair<std::string, int> by distributing the name throughout the values. My naive attempt looks something like this:
auto result = data | asFoo() | view::transform([](auto&& foo) {
const auto& name = foo.name;
const auto& values = foo.values;
return values | view::transform([name](auto&& value) {
return std::make_pair(name, value);
}
}) | view::join;
However, this results in the undefined behavior because values is freed. The only way that I have been able to get around this is to make values a std::shared_ptr and to capture it in the lambda passed to view::transform to preserve it's lifetime. That seems like an inelegant solution.
I think what I am looking for is a view that will take ownership of the source collection, but it does not look like range-v3 has that.
Alternatively, I could just create the distributed version using a good old fashioned for-loop, but that does not appear to work with view::join:
auto result = data | asFoo() | view::transform([](auto&& foo) {
const auto& name = foo.name;
const auto& values = foo.values;
std::vector<std::pair<std::string, std::string>> distributedValues;
for (const auto& value : values) {
distributedValues.emplace_back(name, value);
}
return distributedValues;
}) | view::join;
Even if this did work with view::join, I also think that the mixed metaphor of ranges and loops is also inelegant.

Views do not own the data they present. If you need to ensure the persistence of the data, then the data itself needs to be preserved.
auto createRange() {
//We're using a pointer to ensure that the contents don't get moved around, which might invalidate the view
std::unique_ptr<std::unordered_set<int>> is_ptr = std::make_unique<std::unordered_set<int>>({1,2,3,4,5,6});
auto & is = *is_ptr;
auto view = is | view::transform([](auto&& i) {return i;});
return std::make_pair(view, std::move(is_ptr));
}
int main() {
auto[rng, data_ptr] = createRange();
ranges::for_each(rng, [](auto&& i) {
std::cout << std::to_string(i) << std::endl;
});
}
An alternate method is to make sure the function is provided the data set from which the view will be created:
auto createRange(std::unordered_set<int> & is) {
return is | view::transform([](auto&& i) {return i;});
}
int main() {
std::unordered_set<int> is = {1,2,3,4,5,6};
auto rng = createRange(is);
ranges::for_each(rng, [](auto&& i) {
std::cout << std::to_string(i) << std::endl;
});
}
Either solution should broadly represent what your solution for your project will need to do.

Related

Use structure binding for YAML::Node

It is possible to use structure binding when we want to iterate through YAML::Node?
Current code:
for(auto it = node.begin(); it != node.end(); ++it)
{
auto a = it->first.as<std::string>();
auto b = it->second;
// Some code bellow
}
Range-based for loop also works fine:
for(const auto& n : node) {
auto a = n.first.as<std::string>();
auto b = n.second;
// Some code bellow
}
I wish to get something like that:
for(auto [a,b] : node)
{
// Some code bellow
}
Is that possible and how can I use structure binding with YAML::Node? The reason for the change is more readable code. This type of code is used in multiple places and structure binding is a good way to implement a prettier solution.

How to wrap several boolean flags into struct to pass them to a function with a convenient syntax

In some testing code there's a helper function like this:
auto make_condiment(bool salt, bool pepper, bool oil, bool garlic) {
// assumes that first bool is salt, second is pepper,
// and so on...
//
// Make up something according to flags
return something;
};
which essentially builds up something based on some boolean flags.
What concerns me is that the meaning of each bool is hardcoded in the name of the parameters, which is bad because at the call site it's hard to remember which parameter means what (yeah, the IDE can likely eliminate the problem entirely by showing those names when tab completing, but still...):
// at the call site:
auto obj = make_condiment(false, false, true, true); // what ingredients am I using and what not?
Therefore, I'd like to pass a single object describing the settings. Furthermore, just aggregating them in an object, e.g. std::array<bool,4>.
I would like, instead, to enable a syntax like this:
auto obj = make_smart_condiment(oil + garlic);
which would generate the same obj as the previous call to make_condiment.
This new function would be:
auto make_smart_condiment(Ingredients ingredients) {
// retrieve the individual flags from the input
bool salt = ingredients.hasSalt();
bool pepper = ingredients.hasPepper();
bool oil = ingredients.hasOil();
bool garlic = ingredients.hasGarlic();
// same body as make_condiment, or simply:
return make_condiment(salt, pepper, oil, garlic);
}
Here's my attempt:
struct Ingredients {
public:
enum class INGREDIENTS { Salt = 1, Pepper = 2, Oil = 4, Garlic = 8 };
explicit Ingredients() : flags{0} {};
explicit Ingredients(INGREDIENTS const& f) : flags{static_cast<int>(f)} {};
private:
explicit Ingredients(int fs) : flags{fs} {}
int flags; // values 0-15
public:
bool hasSalt() const {
return flags % 2;
}
bool hasPepper() const {
return (flags / 2) % 2;
}
bool hasOil() const {
return (flags / 4) % 2;
}
bool hasGarlic() const {
return (flags / 8) % 2;
}
Ingredients operator+(Ingredients const& f) {
return Ingredients(flags + f.flags);
}
}
salt{Ingredients::INGREDIENTS::Salt},
pepper{Ingredients::INGREDIENTS::Pepper},
oil{Ingredients::INGREDIENTS::Oil},
garlic{Ingredients::INGREDIENTS::Garlic};
However, I have the feeling that I am reinventing the wheel.
Is there any better, or standard, way of accomplishing the above?
Is there maybe a design pattern that I could/should use?
I think you can remove some of the boilerplate by using a std::bitset. Here is what I came up with:
#include <bitset>
#include <cstdint>
#include <iostream>
class Ingredients {
public:
enum Option : uint8_t {
Salt = 0,
Pepper = 1,
Oil = 2,
Max = 3
};
bool has(Option o) const { return value_[o]; }
Ingredients(std::initializer_list<Option> opts) {
for (const Option& opt : opts)
value_.set(opt);
}
private:
std::bitset<Max> value_ {0};
};
int main() {
Ingredients ingredients{Ingredients::Salt, Ingredients::Pepper};
// prints "10"
std::cout << ingredients.has(Ingredients::Salt)
<< ingredients.has(Ingredients::Oil) << "\n";
}
You don't get the + type syntax, but it's pretty close. It's unfortunate that you have to keep an Option::Max, but not too bad. Also I decided to not use an enum class so that it can be accessed as Ingredients::Salt and implicitly converted to an int. You could explicitly access and cast if you wanted to use enum class.
If you want to use enum as flags, the usual way is merge them with operator | and check them with operator &
#include <iostream>
enum Ingredients{ Salt = 1, Pepper = 2, Oil = 4, Garlic = 8 };
// If you want to use operator +
Ingredients operator + (Ingredients a,Ingredients b) {
return Ingredients(a | b);
}
int main()
{
using std::cout;
cout << bool( Salt & Ingredients::Salt ); // has salt
cout << bool( Salt & Ingredients::Pepper ); // doesn't has pepper
auto sp = Ingredients::Salt + Ingredients::Pepper;
cout << bool( sp & Ingredients::Salt ); // has salt
cout << bool( sp & Ingredients::Garlic ); // doesn't has garlic
}
note: the current code (with only the operator +) would not work if you mix | and + like (Salt|Salt)+Salt.
You can also use enum class, just need to define the operators
I would look at a strong typing library like:
https://github.com/joboccara/NamedType
For a really good video talking about this:
https://www.youtube.com/watch?v=fWcnp7Bulc8
When I first saw this, I was a little dismissive, but because the advice came from people I respected, I gave it a chance. The video convinced me.
If you look at CPP Best Practices and dig deeply enough, you'll see the general advice to avoid boolean parameters, especially strings of them. And Jonathan Boccara gives good reasons why your code will be stronger if you don't directly use the raw types, for the very reason that you've already identified.

Call different processing functions for attributes in an XML element

When handling XML attributes in C++, how should different operations be run for different attributes?
Currently, I have something like this:
// get list of attributes for an XML element into member called 'attributes'
// ...
// run appropriate functions for each attribute
for (auto attribute : attributes)
{
auto name = attribute.name;
auto value = attribute.value;
if (name == "x")
doSomethingWithX(value);
else if (name == "y")
doSomethingWithY(value);
}
For just a few attribute names, this isn't so bad - but with a larger number (>15) this starts to look messy and I'm concerned about performance issues.
What might be a better way of handling XML attributes like this?
You can use a std::unordererd_map<std::string, std::function<void (const std::string&)>> and set it up with appropriate lambda functions:
std::unordererd_map<std::string, std::function<void (const std::string&)>> attrProcessors = {
{ "X", [](const std::string& value) {
// Do something with value
} } } ,
{ "Y", [](const std::string& value) {
// Do something with value
} } }
};
// run appropriate functions for each attribute
for (auto attribute : attributes)
{
auto name = attribute.name;
auto value = attribute.value;
auto processorEntry = attrProcessors.find(name);
if(processorEntry != attrProcessors.end()) {
(*processorEntry).second(value);
}
}
I am not so sure though that maintenace of the map entries would be easier to read than the if / else if cascade.
On the other hand you won't need to create an extra function for each attribute name.

Function returning a container containing specific elements of input container

I have a vector or list of which I only want to apply code to specific elements. E.g.
class Container : public std::vector<Element*>
Or
class Container : public std::list<Element*>
And:
Container newContainer = inputContainer.Get(IsSomething);
if (!newContainer.empty()) {
for (Element* const el: newContainer ) {
[some stuff]
}
} else {
for (Element* const el : inputContainer) {
[some stuff]
}
}
I've written a member function Get() as follows.
template<typename Fn>
auto Container::Get(const Fn& fn) const {
Container output;
std::copy_if(cbegin(), cend(), std::inserter(output, output.end()), fn);
return output;
}
and IsSomething would be a lambda, e.g.
auto IsSomething= [](Element const* const el)->bool { return el->someBool; };
From performance perspective: Is this a good approach? Or would it be better to copy and remove?
template<typename Fn>
auto Container::Get(const Fn& fn) const {
Container output(*this);
output.erase(std::remove_if(output.begin(), output.end(), fn), end(output));
return output;
}
Or is there a better approach anyhow?
edit: different example
As my previous example can be written in a better way, let's show a different example:
while (!(container2 = container1.Get(IsSomething)).empty()&&TimesFooCalled<SomeValue)
{
Container container3(container2.Get(IsSomething));
if (!container3.empty()) {
Foo(*container3.BestElement());
} else {
Foo(*container2.BestElement());
}
}
Not answering your direct question, but note that you can implement the original algorithm without copying anything. Something like this:
bool found = false;
for (Element* const el: inputContainer) {
if (IsSomething(el)) {
found = true;
[some stuff]
}
}
if (!found) {
for (Element* const el : inputContainer) {
[some stuff]
}
}
The usual pattern that I use is something like this:
for(auto const * item : inputContainer) if(IsSomething(item)) {
// Do stuff with item
}
This is usually good enough, so other approaches seem overkill.
For better performance it is always better not to copy or remove elements from the list you get. In my experience it's even faster if you only go through the list once, for caching reasons. So here is what I would do to find one or the other "best" value from a list:
auto const isBetter = std::greater<Element>();
Element const * best = nullptr, const * alt_best = nullptr;
for(Element const * current : inputContainer) {
if(IsSomething(current)) {
if(!best || isBetter(*best, *current)) best = current;
} else {
if(!alt_best || isBetter(*alt_best, *current)) alt_best = current;
}
}
if(best) {
// do something with best
} else if(alt_best) {
// do something with alt_best
} else {
// empty list
}
If you find yourself doing this a lot or you want to make this part of your class's interface you could consider writing an iterator that skips elements you don't like.
If you actually want to remove the item from the list, you could do something like this:
inputContainer.erase(std::remove_if(std::begin(inputContainer), std::end(inputContainer),
[](Element const *item) {
if(IsSomething(item)) {
// Do something with item
return true;
}
return false;
}
));

A more elegant way for a template function grouping values?

The following code groups values for any container with a generic grouping lambda:
template<class Iterator, class GroupingFunc,
class T = remove_reference_t<decltype(*declval<Iterator>())>,
class GroupingType = decltype(declval<GroupingFunc>()(declval<T&>()))>
auto groupValues(Iterator begin, Iterator end, GroupingFunc groupingFunc) {
map<GroupingType, list<T>> groups;
for_each(begin, end,
[&groups, groupingFunc](const auto& val){
groups[groupingFunc(val)].push_back(val);
} );
return groups;
}
With the following usage:
int main() {
list<string> strs = {"hello", "world", "Hello", "World"};
auto groupOfStrings =
groupValues(strs.begin(), strs.end(),
[](auto& val) {
return (char)toupper(val.at(0));
});
print(groupOfStrings); // assume a print method
list<int> numbers = {1, 5, 10, 24, 13};
auto groupOfNumbers =
groupValues(numbers.begin(), numbers.end(),
[](int val) {
int decile = int(val / 10) * 10;
return to_string(decile) + '-' + to_string(decile + 9);
});
print(groupOfNumbers); // assume a print method
}
I am a bit reluctant regarding the (over?)-use of declval and decltype in groupValues function.
Do you see a better way for writing it?
(Question is mainly for better style and clarity unless of course you see any other issue).
Code: http://coliru.stacked-crooked.com/a/f65d4939b402a750
I would probably move the last two template parameters inside the function, and use std::result_of to give a slightly more tidy function:
template <typename T>
using deref_iter_t = std::remove_reference_t<decltype(*std::declval<T>())>;
template<class Iterator, class GroupingFunc>
auto groupValues(Iterator begin, Iterator end, GroupingFunc groupingFunc) {
using T = deref_iter_t<Iterator>;
using GroupingType = std::result_of_t<GroupingFunc(T&)>;
std::map<GroupingType, std::list<T>> groups;
std::for_each(begin, end, [&groups, groupingFunc](const auto& val){
groups[groupingFunc(val)].push_back(val);
});
return groups;
}
live demo