Modern C++ - how to implement FirstOrDefault with std::optional and references - c++

I've picked up C++ again after spending years with C# and Javascript/Typescript.
I've gotten very used to writing code that manipulates and queries containers with algorithms, such as:
C#
var mocData = Enumerable.Range(0, 100)
.Where(n => n % 2 == 1)
.Select(n => new Item(n))
.ToList();
Javascript (using Lodash <3 )
const mocData = _.chain(_.range(0, 100))
.filter(n => n % 2 == 1)
.map(n => ({ n: `Item #${n}` }))
.value();
Now, C++ is a very different beast and what I'm trying to do, without much success (from a clean syntax/low verbosity point of view), is write a wrapper for STL's functions that allow me to work on items inside the container, instead of their copies, using value semantics, while also accounting for "nullability (ie std::optional wrapped values). For example, a find function if quite easy to write if you don't care about nullability. Here is how I want to use it, and how it is implemented:
template<typename T, typename Predicate>
auto find(const std::vector<T>& items, Predicate pred) -> T& {
auto it = std::find_if(items.begin(), items.end(), pred);
if (it == items.end()) {
throw std::runtime_error{ "Sequence contains no matching elements." };
}
return *it;
}
std::vector<MyClass> items = { ... };
const auto& item = find(items, [](const MyClass& o) { return o... });
++item.count; // Modifies the item inside of the container
Now, if I wanted to account for nullability, as in C# or javascript:
C#
var item = items.FirstOrDefault(o => o...);
item?.DoSomething();
Javascript
const item = _.find(items, o => o...);
item?.doSomething();
I have to use, in C++, std::optional. And to avoid a copy (so as to be able to modify the item in the container!!), I have to return std::optional. But std::optional can't be used with T& directly, so I have to use std::reference_wrapper as its type:
template<typename T>
using Ref = std::reference_wrapper<T>;
template<typename T, typename Predicate>
auto firstOrDefault(std::vector<T>& vec, Predicate pred) -> std::optional<Ref<T>> {
auto it = std::find_if(vec.begin(), vec.end(), pred);
if (it == vec.end()) {
return std::nullopt;
}
return std::ref(*it);
}
Now, the ugly part is using the returned value:
const auto item = firstOrDefault(items, predicate...);
if (item.has_value()) {
item
.value() // unwrap the ref from std::optional
.get() // unwrap T& from std::reference_wrapper<T>
.do_something() // jeeeez so hard to use it!!
}
I know I could use pointers, and that there's nothing bad with using non owning pointers as references, maybe using the C++ Core Guidelines's type... but references were made for maintaining value semantics, and I'd like to use them even though they don't play well with containers and wrappers in the STL.
Is there a good way to achieve this?
EDIT: I've modified the title to better express that I do not want a LINQ-like library, I'm trying to understand if with modern C++20 it is possible to work with nullability and references (not pointers) with a decent syntax.

Related

Generic way to use fs::recursive_directory_iterator() and fs::directory_iterator()

I need to iterate over folder either recursively or not (given the boolean parameter). I have discovered there is fs::recursive_directory_iterator() and also fs::directory_iterator(). In Java, I would expect them to implement the same interface or share the common ancestor so that I could substitute the needed one. But for some reason the two iterators do not share the common ancestor, forcing the to write the code like:
if (recursive_) {
path = recursive_iterator_->path();
recursive_iterator_++;
} else {
path = plain_iterator_->path();
plain_iterator_++;
}
I cannot believe this is how it is supposed to work. I also initially assumed there are some options to turn off recursion for recursive_directory_iterator but seems no any between std::filesystem::directory_options.
The value is not known at the compile time. I think it should be possible to use something like a closure or even subclass with virtual method but looks a bit like overkill.
Should I simply use conditionals switching between the two iterators as needed, or there are better approaches?
implement the same interface
They do. They are both InputIterators, that dereference to const std::filesystem::directory_entry&.
C++ avoids virtual by default.
You can use boost::any_range to type erase the recursiveness.
template <typename... Args>
auto make_directory_range(bool recursive, Args... args) {
return recursive
? boost::make_iterator_range(fs::recursive_directory_iterator(args...), fs::recursive_directory_iterator()) | boost::adaptors::type_erased()
: boost::make_iterator_range(fs::directory_iterator(args...), fs::directory_iterator());
}
using iterator_t = decltype(make_directory_range(true).begin());
auto range = make_directory_range(recursive_, args...);
iterator_t iterator = range.begin();
iterator_t end = range.end();
The usual way of dealing with a static polymorphism situation like this is to use a helper template:
template<class F,class ...AA>
void for_each_file(F f,bool rec,AA &&...aa) {
const auto g=[&](auto end) {
std::for_each(decltype(end)(std::forward<AA>(aa)...),
end,std::move(f));
};
if(rec) g(fs::recursive_directory_iterator());
else g(fs::directory_iterator());
}
std::size_t count(const fs::path &d,bool rec) {
std::size_t n=0;
for_each_file([&](fs::directory_entry) {++n;},rec,d);
return n;
}
This approach does have limitations: it makes it harder to break out of the “loop”, for example.

Return collection via iterators from template method

Let's say (for simplicity) that I want to pass collection to method, the method will apply some func to every element of collection and return this collection. E.g. in C# this will looks like this
IEnumerable<Tout> Transform<Tin, Tout>(IEnumerable<Tin> collection,
Func<Tin, Tout> func)
{
return collection.Select(x => func(x));
}
My goal is to write equivalent function in C++. According to this question I should pass two iterators to function which will represent boundaries of input collection. This solves problem of passing collection. But how to return collection?
I was thinking that I should apply same logic and return pair of iterator from function which will represent returning collection.
Here is how I tried to write equivalent function:
template<typename ForwardIterator, typename ReturnIterator>
std::pair<ReturnIterator, ReturnIterator> Transform(
ForwardIterator begin, ForwardIterator end,
std::function <
typename std::iterator_traits<ReturnIterator>::value_type
(typename std::iterator_traits<ForwardIterator>::value_type)
> func)
{
using InputType = std::iterator_traits<ForwardIterator>::value_type;
using RetType = std::iterator_traits<ReturnIterator>::value_type;
std::vector<RetType> ans;
std::transform(begin, end, std::back_inserter(ans),
[&](InputType el) -> RetType { return func(el); } );
return { std::begin(ans), std::end(ans) };
}
int main()
{
// Simple example -> converts every int to string from inputCollection
std::vector<int> inputCollection = { 1,2,3 };
auto retCollecction = Transform<std::vector<int>::iterator, std::vector<std::string>::iterator>
(std::begin(inputCollection),
std::end(inputCollection),
[](int el)-> std::string {return std::to_string(el); });
}
Obviously this is not good since output collection is disposed as soon as I exit function and iterators points to nothing. So, how to fix this, and what should be the best way to write this in C++.
Note: I don't want to pass and return vector<T> or some other specific collection. I would like a general approach which can deal with any type of collections.
The general C++ approach is to accept an output iterator. Let the caller decide where the output should go.
The ranges library uses the concept of, well, ranges - a pair of start and end iterator. If you plan to write LINQ-like code a lot, you should probably look into it and base your code around its concepts:
https://github.com/ericniebler/range-v3
The (current standard library) C++ way is to accept an output iterator, see std::transform.
The (future) C++ way is to return a Range value, see ranges::transform
Note that you can wrap an output iterator algorithm in an asymmetric coroutine
to get a range-like value.
template<typename InputIterator, typename Func>
auto transform(InputIterator begin, InputIterator end, Func func)
{
using coro_t = boost::coroutines2::coroutine<decltype(func(*begin))>;
return coro_t::pull_type([=](coro_t::push_type& yield)
{
std::transform(begin, end, yield, func);
});
}

In C++17 can an if statement with an initializer be used to unpack an optional?

I'm writing some code using std::optional's and am wondering if C++17's 'if statements with initializers' will be able to help unpack values?
std::optional<int> optionalInt = GetOptionalInt();
I'm making up the function Unpack here:
if( auto [value, has_value] = optionalInt.Unpack(); has_value )
{
// Use value here.
}
But, my question is. Will C++17 'if statement with initializer' help here? If so, how would it be coded?
Update, this is actually mainly an issue when using optional which is extremely easy to misuse because the optional and *optional both return bools and you don't get any compiler warning when somebody trys to access the value and forgets the *.
There is not, and cannot possibly be, such an Unpack() function.
But you could certainly do:
if (std::optional<int> o = GetOptionalInt(); o) {
// use *o here
}
though the extra o check is kind of redundant.
This is one of those places where it'd be nice if optional<T> modeled a container of at most one element, so that you could do:
for (int value : GetOptionalInt()) {
// possibly not entered
}
but we don't have that interface.
In order for this to work, there has to be a value for the unpacked value if it isn't there.
So
template<class T, class U>
std::pair< T, bool > unpack_value( std::optional<T> const& o, U&& u ) {
return { o.value_or(std::forward<U>(u)), (bool)o } )
}
would do what you wanted.
But as an optional already returns if it is engaged in a bool context you really should just:
if (auto i = get_optional())
then use *i within the body.
...
Now if optional stated that operator* returned a reference, and that return value was defined but accessing it was not defined when it was not engaged, then you could write an Unpack method or function that doesn't require a default value.
As far as I am aware this is not true. And as it doesn't really add anything, I don't see why it should be true.
Maybe this would work:
auto optValue = getOptional();
if (auto value = *optValue; optValue) { ...use value here... }

Using RTTI hash with a template function

I understand that templates are compile-time, and typeinfo-related are runtime, but I'm wondering if I can achieve my particular task.
I have a factory method using templates to create objects of a particular type; I also have a preloader (reading data from disk), which determines what type of object is to be created, but doesn't actually create it - that's the responsibility of the creator, and is executed on demand.
void Creator::Spawn(Preloader* pl)
{
std::unordered_map<size_t, std::type_index> hashmap;
// assume ObjectType is simply a wrapper around a hash
hashmap[ObjectType<Type1>::GetType().Hash()] = typeid(Type1);
hashmap[ObjectType<Type2>::GetType().Hash()] = typeid(Type2);
for ( auto& const i : pl->GetPreloadInfo() )
{
size_t hash = i->type_hash.Hash();
// similar-to-desired usage
FactoryCreate<hashmap[hash]>();
}
}
Is there any way to achieve this? Obviously I can do manual checks for each, like below, but it's nasty at best.
// poor, manual implementation
if ( hash == ObjectType<Type1>::GetType().Hash() )
FactoryCreate<Type1>();
else if ( hash == ObjectType<Type2>::GetType().Hash() )
FactoryCreate<Type2>();
Everything I've tried so far has hit the runtime vs compile-time differences, though I'm definitely not aware of all the newest C++11 tricks that may assist (C++14 not usable).
Partially related question here: Use data type (class type) as key in a map
Assuming the hash part is set in stone, you can create a map from those type hashes to your factory functions directly:
using map_type = std::unordered_map<size_t, std::function<void()>>;
template <class... Ts>
map_type create_hash_map() {
map_type map;
// emplace (hash<T>, FactoryCreate<T>) for each T
using swallow = int[];
(void)swallow{0,
(void(
map.emplace(ObjectType<Ts>::GetType().Hash(),
[]{ FactoryCreate<Ts>(); }
)
), 0)...
};
return map;
}
Then we can just use that map directly:
void Creator::Spawn(Preloader* pl)
{
static auto hashmap = create_hash_map<Type1, Type2>();
for ( auto& const i : pl->GetPreloadInfo() )
{
size_t hash = i->type_hash.Hash();
hashmap[hash]();
}
}
That doesn't have error-checking, so if the hash isn't actually in the map, you'll get a bad_function_call exception from std::function. If you need error checking, you can instead do a lookup in the map first:
auto it = hashmap.find(hash);
if (it != hashmap.end()) {
(it->second)();
}
else {
// error!
}

Boost::multi_index with map

I have a question about modifying elements in boost::multi_index container.
What I have is the structure, containing some pre-defined parameters and
a number of parameters, which are defined at run-time, and stored in a map.
Here is a simplified version of the structure:
class Sdata{
QMap<ParamName, Param> params; // parameters defined at run-time
public:
int num;
QString key;
// more pre-defined parameters
// methods to modify the map
// as an example - mock version of a function to add the parameter
// there are more functions operating on the QMAP<...>, which follow the same
// rule - return true if they operated successfully, false otherwise.
bool add_param(ParamName name, Param value){
if (params.contains(name)) return false;
params.insert(name, value);
return true;
}
};
Now, I want to iterate over different combinations of the pre-defined parameters
of Sdata. To do this, I went for boost::multi_index:
typedef multi_index_container<Sdata,
indexed_by <
// by insertion order
random_access<>,
//by key
hashed_unique<
tag<sdata_tags::byKey>,
const_mem_fun<Sdata, SdataKey, &Sdata::get_key>
>,
//by TS
ordered_non_unique<
tag<sdata_tags::byTS>,
const_mem_fun<Sdata, TS, &Sdata::get_ts>
>,
/// more keys and composite-keys
>//end indexed by
> SdataDB;
And now, I want to access and modify the parameters inside the QMap<...>.
Q1 Do I get it correctly that to modify any field (even those unrelated to
the index), one needs to use functors and do something as below?
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
l.modify(it, Functor(...))
Q2 How to get the result of the method using the functor? I.e., I have a functor:
struct SdataRemoveParam : public std::unary_function<Sdata, void>{
ParamName name;
SdataRemoveParam(ParamName h): name(h){}
void operator ()(Sdata &sdata){
sdata.remove_param (name); // this returns false if there is no param
}
};
How to know if the remove_param returned true or false in this example:
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
l.modify(it, SdataRemoveParam("myname"));
What I've arrived to so far is to throw an exception, so that the modify
method of boost::multi_index, when using with Rollback functor will return
false:
struct SdataRemoveParam : public std::unary_function<Sdata, void>{
ParamName name;
SdataRemoveParam(ParamName h): name(h){}
void operator ()(Sdata &sdata){
if (!sdata.remove_param (name)) throw std::exception("Remove failed");
}
};
// in some other place
Sdatas_byKey const &l = sdatas.get<sdata_tags::byKey>();
auto it = l.find(key);
bool res = l.modify(it, SdataRemoveParam("myname"), Rollback);
However, I do not like the decision, because it increases the risk of deleting
the entry from the container.
Q3 are there any better solutions?
Q1 Do I get it correctly that to modify any field (even those
unrelated to the index), one needs to use functors and do something as
below?
Short answer is yes, use modify for safety. If you're absolutely sure that the data you modify does not belong to any index, then you can get by with an ugly cast:
const_cast<Sdata&>(*it).remove_param("myname");
but this is strongly discouraged. With C++11 (which you seem to be using), you can use lambdas rather than cumbersome user-defined functors:
Sdatas_byKey &l = sdatas.get<sdata_tags::byKey>(); // note, this can't be const
auto it = l.find(key);
l.modify(it, [](Sdata& s){
s.remove_param("myname");
});
Q2 How to get the result of the method using the functor?
Again, with lambdas this is very simple:
bool res;
l.modify(it, [&](Sdata& s){
res=s.remove_param("myname");
});
With functors you can do the same but it requires more boilerplate (basically, have SdataRemoveParam store a pointer to res).
The following is just for fun: if you're using C++14 you can encapsulate the whole idiom very tersely like this (C++11 would be slightly harder):
template<typename Index,typename Iterator,typename F>
auto modify_inner_result(Index& i,Iterator it,F f)
{
decltype(f(std::declval<typename Index::value_type&>())) res;
i.modify(it,[&](auto& x){res=f(x);});
return res;
}
...
bool res=modify_inner_result(l,it, [&](Sdata& s){
return s.remove_param("myname");
});