Need to Total Fields From a Container of structs - c++

This is more of a code clenliness question, cause I already have an example here. I'm doing this a ton in code and the creation of all these lambdas (some of which are the same) has begun to irk me.
So given the struct:
struct foo {
int b() const { return _b; }
int a() const { return _a; }
int r() const { return _r; }
const int _b;
const int _a;
const int _r;
};
I have a container of pointers to them, let's say vector<foo*> foos, now I want to go through the container and get the sum of one of the fields.
As an example if I wanted the field _r, then my current approach is to do this:
accumulate(cbegin(foos), cend(foos), 0, [](const auto init, const auto i) { return init + i->r(); } )
I'm writing this line everywhere. Can any improvement be made upon this? I'd really like to write something like this:
x(cbegin(foos), cend(foos), mem_fn(&foo::r));
I don't think the standard provides anything like that. I could obviously write it, but then it would require the reader to go figure out my suspect code instead of just knowing what accumulate does.

Instead of writing a custom accumulate, I suggest writing a custom functor generator, that returns a functor that can be used as an argument to std::accumulate.
template<class Fun>
auto mem_accumulator(Fun member_function) {
return [=](auto init, auto i) {
return init + (i->*member_function)();
};
}
then
accumulate(cbegin(foos), cend(foos), 0, mem_accumulator(&foo::r));
A few variations:
For containers of objects:
template<class MemFun>
auto mem_accumulator(MemFun member_function) {
return [=](auto init, auto i) {
return init + (i.*member_function)();
};
}
Use data member pointers instead of functions:
template<class T>
auto mem_accumulator(T member_ptr) {
return [=](auto init, auto i) {
return init + i->*member_ptr;
};
}
// ...
accumulator(&foo::_r)
Support functors, rather than member function pointers:
template<class Fun>
auto accumulator(Fun fun) {
return [=](auto init, auto i) {
return init + fun(i);
};
}
// ...
accumulator(std::mem_fun(&foo::r))
Some (all?) of these variations could perhaps be combined to be selected automatically with some SFINAE magic, but that will increase complexity.

There is actually a really elegant way to solve this using Variable Templates which were introduced in c++14. We can templatize a lambda variable using the method pointer as the template argument:
template <int (foo::*T)()>
auto func = [](const auto init, const auto i){ return init + (i->*T)(); };
Passing the func appropriate specialization of func as the last argument to accumulate will have the same effect as writing out the lambda in place:
accumulate(cbegin(foos), cend(foos), 0, func<&foo::r>)
Live Example
Another alternative based off the same templatization premise, which does not require c++14, is the templatized function suggested by StoryTeller:
template <int (foo::*T)()>
int func(const int init, const foo* i) { return init + (i->*T)(); }
Which could also be used by simply passing the method pointer:
accumulate(cbegin(foos), cend(foos), 0, &func<&foo::r>)
Live Example
The specificity required by both these examples has been removed in c++17 where we can use auto for template parameter types: http://en.cppreference.com/w/cpp/language/auto This will allow us to declare func so it can be used by any class, not just foo:
template <auto T>
auto func(const auto init, const auto i) { return init + (i->*T)(); }

Related

How to write function with the matching const modifier on argument and return types?

I want to write a function that extracts a pointer field from a struct. The requirement is that if I pass the struct as a const argument, the returned type should be const. If not, the returned type should not be const.
For instance,
struct S {
char *p;
};
// approach 1: two overload functions with duplicate body
auto extract(S &input) -> int * {
return reinterpret_cast<int *>(input.p + 12);
}
auto extract(const S &input) -> const int * {
return reinterpret_cast<const int *>(input.p + 12);
}
// approach 2: macro
#define macro_extract(input) (reinterpret_cast<int *>(input.p + 12))
Is there any trick in template or latest C++ standard that can write a strongly typed function without duplicating the body?
EDIT:
Changed the example a bit to reflect more accurately of the real problem.
Here's a solution with a single function template:
template<typename T,
typename = std::enable_if_t<
std::is_same_v<
std::remove_cv_t<
std::remove_reference_t<T>>, S>>>
auto extract(T&& input)
-> std::conditional_t<
std::is_const_v<
std::remove_reference_t<T>>, int const *, int *>
{
return input.p;
}
Here's a demo.
I think it goes without saying that you'd be better off with an overload set. If the function body is large, you can still call the non-const version from the const overload, and add the const there.
if constexpr and auto as return type solution:
#include <type_traits>
struct S {
int *p;
};
template<typename T>
auto extract(T &&input) {
static_assert(std::is_same_v<std::decay_t<decltype(input)>,S>, , "Only struct S is supported");
if constexpr(!std::is_const_v<std::remove_reference_t<decltype(input)>>) {
return input.p;
} else {
return const_cast<const int*>(input.p);
}
}
int main () {
S i;
using t = decltype(extract(i));
static_assert(std::is_same_v<t,int*>);
S const i_c{0};
using t_c = decltype(extract(i_c));
static_assert(std::is_same_v<t_c,const int*>);
return 0;
}
PLZ look at the ISO proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4388.html
And the std::experimental::propagate_const spec:
https://en.cppreference.com/w/cpp/experimental/propagate_const
Or one can implement his own version of propagate_const.
have fun,
FM
SFINAE should be able to do this. The approximate format is:
template<class T,
class allow=std::enable_if_t<std::is_base_of_v<S, T>>>
auto extract(T&& input) -> decltype(input.p) {
return input.p;
}
Basically using universal forwarding references to make it work for anything: S, S&, const S&, S&&, volatile S&, etc.

Can I forward (the type of) a generic overloaded function without creating syntax monsters?

This is just an educational question, which could otherwise be avoided entirely by leveraging on tools such as range-v3.
Anyway, consider this example in which a variadic number of containers is passed to a function which returns a tuple of iterators:
#include <tuple>
#include <iostream>
#include <vector>
template <typename ...T>
auto begin(T&... containers) { return std::tuple( begin(containers)... ); }
int main() {
std::vector<int> a{1,2,3};
std::vector<long> b{1000,2000,3000};
auto bg = begin(a,b);
(void) bg;
return 0;
}
Quite a lot of code duplication will be produced by adding the functions for all the other iterator makers (std::[end, cbegin, cend, rbegin, rend]). Therefore I was looking for a way to forward the generic iterator maker function into my function.
I managed to come up with this:
template <auto F, typename ...T>
auto make(T&... containers) { return std::tuple( F(containers)... ); }
// called as this:
auto bg = make<[](auto& c){return std::begin(c);}> (a,b);
...which is more general but comes with an horrendous syntax for the user, Ideally the call should be something like:
auto bg = make<std::begin>(a, b); // or
auto bg = make(std::begin, a, b);
but I have not been able to make these beauties work...
but I have not been able to make these beauties work...
There is no way to make those beauties work currently. The root of it all is that std::begin et al are not functions. They are function templates. Meaning they represent not a single function but an entire family of them. The same is true when you have regular overloads as well. The moment a function name means more than a single function, it can't be passed. An overload set is not a tangible thing we can pass around like a type or a function reference. It's not a callable really.
Wrapping the actual overloaded call into a lambda bypasses the issue entirely. Because a lambda is an object with a type, and those can be passed around just fine. This essentially lifts the overload set up from being a second class citizen. But it comes with boilerplate.
There was a proposal made (p1170) to automatically lift an overload set into a callable, but so far it didn't seem to gain traction. So C++20 doesn't have the means.
As for the boilerplate, we can cut on it if we are willing to employ macros. A simple macro that lifts an overload set correctly can look something like this:
#define LIFT(...) [](auto&& ...args) \
noexcpet(noexcpet(__VA_ARGS__(std::forward<decltype(args)>(args)...))) \
-> decltype(auto) { \
return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
}
Granted, that's a lot of boilerplate by itself, but it handles the exception specification, as well as return type deduction for functions that don't return by value. It also perfect forwards. So while it is indeed fairly ugly, it allows us to write:
auto bg = make(LIFT(std::begin), a, b);
You could wrap those functions within lambdas so you could use it in the next fashion
make(std::begin, a, b);
i.e
template <typename F, typename ...T>
decltype(auto) make(F func, T&... containers) { return std::tuple( func(containers)... ); }
namespace tl {
auto begin = [](auto& c) {
return std::begin(c);
};
}
int main() {
std::vector<int> a{1,2,3};
std::vector<long> b{1000,2000,3000};
auto bg = make(tl::begin, a, b);
(void) bg;
cout << *++std::get<0>(bg) << ' ' << *std::get<1>(bg);
return 0;
}
Depending on your definition of monster, this is easily achievable:
int main()
{
auto v1 = std::vector{1,2,3};
auto v2 = std::vector{4,5,6};
auto begins = std::tie(v1, v2) >> notstd::begin;
auto ends = std::tie(v1, v2) >> notstd::end;
return 0;
}
Here's the boilerplate:
#include <vector>
#include <tuple>
#include <utility>
namespace notstd
{
namespace detail
{
template<class Tuple, class Function, std::size_t...Is>
auto transform_elements(Tuple&& tup, Function f, std::index_sequence<Is...>)
{
return std::make_tuple(f(std::get<Is>(std::forward<Tuple>(tup)))...);
}
}
template<class Tuple, class Transform>
auto operator >> (Tuple&& tup, Transform t)
{
using tuple_type = std::decay_t<Tuple>;
constexpr auto size = std::tuple_size<tuple_type>::value;
return detail::transform_elements(std::forward<Tuple>(tup),
t,
std::make_index_sequence<size>());
}
constexpr auto begin = [](auto&& x)
{
return std::begin(x);
};
constexpr auto end = [](auto&& x)
{
return std::end(x);
};
}
This is by no means a style recommendation.

C++ Convert tuple of homogeneous wrapped type to tuple of raw type

I'd like to call std::apply() to a function; however, I am unable to because the std::tuple I use is currently wrapped. For example:
#include <tuple>
template <class T>
struct wrapped
{
wrapped(T t) : t(t) {}
T t;
};
template <class T, class ... Args>
struct delay_call
{
T(*callback)(Args...);
std::tuple<Args...> params;
delay_call(T(*callback)(Args...), Args ... params) :
callback(callback), params(params...)
{}
T call()
{
return std::apply(callback, params);
}
};
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
std::tuple<Args...> params; // = w_params.t
return std::apply(callback, actual_params);
}
};
float saxpy(float a, float x, float y)
{
return a * x + y;
}
int main()
{
float a = 1, x = 2, y = 3;
delay_call delay_saxpy(saxpy, a, x, y);
wrapped w_a = 1.f, w_x = 2.f, w_y = 3.f;
delay_call_with_wrap w_delay_saxpy(saxpy, w_a, w_x, w_y);
float result = delay_saxpy.call();
float w_result = w_delay_saxpy.call();
}
the delay_call struct works as expected; however, I am unsure how to go about extracting the actual value of each tuple element and giving that to std::apply() to execute.
In short, for delay_call_with_wrap::call, how would I convert std::tuple<wrapped<Args>...> to a std::tuple<Args...>?
I would avoid std::apply completely and call the callback directly by unpacking the tuple using std::index_sequence:
template <std::size_t ...I> T call_low(std::index_sequence<I...>)
{
return callback(std::get<I>(w_params).t...);
}
T call()
{
return call_low(std::make_index_sequence<sizeof...(Args)>{});
}
In short, for delay_call_with_wrap::call, how would I convert std::tuple<wrapped<Args>...> to a std::tuple<Args...>?
It seems to me is better avoid std::apply() using the old std::make_index_sequence/std::index_sequence way (see HolyBlackCat answer).
But, if you really want to use std::apply(), you can call it a first time to unwrap the tuple (to get a tuple of unwrapped values) and then call is as usual.
I mean something as
T call ()
{
auto actual_params = std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params);
return std::apply(callback, actual_params);
}
or, in a single call, directly
T call()
{
return std::apply(callback,
std::apply([](auto ... wt){ return std::make_tuple(wt.t...); },
w_params));
}
This solution is reasonable, IMHO, if the w_param member is constant so you can calculate the actual_params one time for all and make it static
Probably not the best solution for use in practice, but here's one using a variadically templated lambda to avoid index_sequence:
template <class T, class ... Args>
struct delay_call_with_wrap
{
T(*callback)(Args...);
std::tuple<wrapped<Args>...> w_params;
delay_call_with_wrap(T(*callback)(Args...), wrapped<Args> ... w_params) :
callback(callback), w_params(w_params...)
{}
T call()
{
auto helper = [this] <class ... Args_> (wrapped<Args_>... args)
{
return callback(args.t...);
};
return std::apply(helper, w_params);
}
};
Demo
The idea is to just provide a function that matches the arguments that std::apply yields here - it needs to take wrapped<Args>.... From there it's trivial to expand the pack while extracting the wrapped value.
We use a lambda because std::apply wants a Callable, so we can't just use another member function. Well, I guess we could overload operator() for delay_call_with_wrap. That would be mildly confusing but at least not limited to C++2a (and missing compiler support) like templated lambdas.

Using constexpr-if in a generic lambda to determine type of a parameter

I have the following problem: I have a class hierarchy with a base class and two sub-classes. I have implemented a resolve_type function that accepts an instance of the base class and a generic lambda (or similar). The function resolves its type and passes it to the lambda. Inside this lambda, I’d like to check the column’s type within a constexpr-if condition in order to exclude certain types. I have tried to do this with constexpr member functions in the sub-classes, which unfortunately didn’t work.
Code:
class AbstractColumn
{
};
template <typename Type>
class DataColumn : public AbstractColumn
{
public:
constexpr bool is_reference_column() { return false; }
void foo() {}
};
class ReferenceColumn : public AbstractColumn
{
public:
constexpr bool is_reference_column() { return true; }
};
template <typename Functor>
resolve_type(const AbstractColumn & col, const Functor & func);
Usage:
AbstractColumn & col = ...;
...
resolve_type(col, [] (const auto & col)
{
// col could be ReferenceColumn, DataColumn<int>, DataColumn<float>, DataColumn<double>, DataColumn<std::string> ...
if constexpr (!col.is_reference_column()) {
col.foo();
}
});
Compiler Error:
Apple LLVM version 8.1.0 (clang-802.0.42)
error: constexpr if condition is not a constant expression
if constexpr (col.is_reference_column()) {
I know that I could use decltype to get the type and then continue using some template magic, but I had hoped to find something that is a bit more readable. My project already uses boost and its hana library, so solutions could also use these two. Does anyone have any ideas?
Use a static constexpr method instead.
It follows a minimal, working example:
#include<type_traits>
struct A {
static constexpr bool is_reference_column() { return false; }
};
int main() {
[](const auto &col) {
if constexpr(std::decay_t<decltype(col)>::is_reference_column()) {
// ...
}
}(A{});
}
Or just inherits from std::true_type/std::false_type:
#include<type_traits>
struct A: std::true_type {};
int main() {
[](const auto &col) {
if constexpr(std::decay_t<decltype(col)>::value) {
// ...
}
}(A{});
}
Or use an intermediate class template instead of redefining continuously is_reference_column:
#include<type_traits>
template<bool refcol>
struct I {
static constexpr bool is_reference_column = refcol;
};
struct A: I<true> {};
int main() {
[](const auto &col) {
if constexpr(std::decay_t<decltype(col)>::is_reference_column) {
// ...
}
}(A{});
}
Plenty of alternatives, but you cannot simply use col in a constant expression just because you declared it as a const reference. col is a runtime instance of a type T, there is no chance you can use it at compile-time as you tried to do.
I think you're overthinking this. You don't need a member function to just identify the type of the object. You can just look at the type. So at a first go, that's simply:
resolve_type(col, [] (const auto& col)
{
if constexpr (hana::typeid_(col) == hana::type_c<ReferenceColumn>) {
col.foo();
}
});
Even simpler would just be to create an overload set and just use overload resolution. There are several implementations of such a mechanism floating around here, it's especially straightforward to write in C++17. Using that:
resolve_type(col, overload(
[](ReferenceColumn const& ref){
ref.foo();
},
[](auto const& other) {
}));

Is it possible to adapt a input parameter to take a pointer instead of a reference?

I am doing something like:
std::vector<T> Ints;
std::find_if(Ints.begin(),Ints.end(),f);
bool f(T * input)
Is it possible to adapt f so it can be used in by the find template?
Use a lambda:
std::find_if(Ints.begin(), Ints.end(), [](const T& t) { return f(&t); });
If you can’t use C++11, you can write a generic adapter using templates:
template <typename T, bool (*predicate)(const T*)>
bool ReferenceToPointer(const T& t) { return predicate(&t); }
std::find_if(Ints.begin(), Ints.end(), ReferenceToPointer<int, f>);
If you can't use a lambda expression, and you need an ad-hoc wrapper, you can always do the following.
void your_func()
{
struct hack
{
static void pred_wrap (int& i) { pred(&i); }
};
std::find_if(Ints.begin(),Ints.end(), hack::pred_wrap);
}
Note that this is more than a bit hackish, and I only offer it for completeness.