Const and non-const functors - c++

This seems like something that ought to be frequently asked and answered, but my search-fu has failed me.
I'm writing a function which I want to accept a generic callable object of some kind (including bare function, hand-rolled functor object, bind, or std::function) and then invoke it within the depths of an algorithm (ie. a lambda).
The function is currently declared like this:
template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
I'm accepting the functor by reference because I want to guarantee that it does not get copied on entry to the function, and thus the same instance of the object is actually called. And it's a const reference because this is the only way to accept temporary objects (which are common when using hand-rolled functors or bind).
But this requires that the functor implement operator() as const. I don't want to require that; I want it to be able to accept both.
I know I can declare two copies of this method, one that accepts it as const and one as non-const, in order to cover both cases. But I don't want to do that as the comments are hiding quite a lot of code that I don't want to duplicate (including some loop constructs, so I can't extract them to a secondary method without just moving the problem).
I also know I could probably cheat and const_cast the functor to non-const before I invoke it, but this feels potentially dangerous (and in particular would invoke the wrong method if the functor intentionally implements both const and non-const call operators).
I've considered accepting the functor as a std::function/boost::function, but this feels like a heavy solution to what ought to be a simple problem. (Especially in the case where the functor is supposed to do nothing.)
Is there a "right" way to satisfy these requirements short of duplicating the algorithm?
[Note: I would prefer a solution that does not require C++11, although I am interested in C++11 answers too, as I'm using similar constructs in projects for both languages.]

Have you tried a forwarding layer, to force inference of the qualifier? Let the compiler do the algorithm duplication, through the normal template instantiation mechanism.
template<typename T, typename F>
size_t do_something_impl(const T& a, F& f)
{
T internal_value(a);
const T& c_iv = interval_value;
// do some complicated things
// loop {
// loop {
f(c_iv, other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something(const T& a, F& f)
{
return do_something_impl<T,F>(a, f);
}
template<typename T, typename F>
size_t do_something(const T& a, const F& f)
{
return do_something_impl<T,const F>(a, f);
}
Demo: http://ideone.com/owj6oB
The wrapper should be completely inlined and have no runtime cost at all, except for the fact that you might end up with more template instantiations (and therefore larger code size), though that will only happen when for types with no operator()() const where both const (or temporary) and non-const functors get passed.

Answer for new relaxed requirements.
In commentary on another answer the OP has clarified/changed the requirements to…
“I'm ok with requiring that if the functor is passed in as a temporary
then it must have an operator() const. I just don't want to limit it
to that, such that if a functor is not passed in as a temporary (and
also not a const non-temporary, of course) then it is allowed to have
a non-const operator(), and this will be called”
This is then not a problem at all: just provide an overload that accepts a temporary.
There are several ways of distinguishing the original basic implementation, e.g. in C++11 an extra default template argument, and in C++03 an extra defaulted ordinary function argument.
But the most clear is IMHO to just give it a different name and then provide an overloaded wrapper:
template<typename T, typename F>
size_t do_something_impl( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
template<typename T, typename F>
size_t do_something( T const& a, F const& f)
{ return do_something_impl( a, f ); }
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{ return do_something_impl( a, f ); }
Note: there's no need to specify the do_something_impl instantiation explicitly, since it's inferred from the lvalue arguments.
The main feature of this approach is that it supports simpler calls, at the cost of not supporting a temporary as argument when it has non-const operator().
Original answer:
Your main goal is to avoid copying of the functor, and to accept a temporary as actual argument.
In C++11 you can just use an rvalue reference, &&
For C++03 the problem is a temporary functor instance as actual argument, where that functor has non-const operator().
One solution is to pass the burden to the client code programmer, e.g.
require the actual argument to be an lvalue, not a temporary, or
require explicit specification that the argument is a temporary, then take it as reference to const and use const_cast.
Example:
template<typename T, typename F>
size_t do_something( T const& a, F& f)
{
T internal_value(a);
// do some complicated things
// loop {
// loop {
f(static_cast<const T&>(internal_value), other_stuff);
// do some more things
// }
// }
return 42;
}
enum With_temp { with_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_temp, F const& f )
{
return do_something( a, const_cast<F&>( f ) );
}
If it is desired to directly support temporaries of const type, to ease the client code programmer's life also for this rare case, then one solution is to just add an additional overload:
enum With_const_temp { with_const_temp };
template<typename T, typename F>
size_t do_something( T const& a, With_const_temp, F const& f )
{
return do_something( a, f );
}
Thanks to Steve Jessop and Ben Voigt for discussion about this case.
An alternative and much more general C++03 way is to provide the following two little functions:
template< class Type >
Type const& ref( Type const& v ) { return v; }
template< class Type >
Type& non_const_ref( Type const& v ) { return const_cast<T&>( v ); }
Then do_something, as given above in this answer, can be called like …
do_something( a, ref( MyFunctor() ) );
do_something( a, non_const_ref( MyFunctor() ) );
Why I didn't think of that immediately, in spite of having employed this solution for other things like string building: it's easy to create complexity, harder to simplify! :)

Related

Universal reference, infer std::list<T> and T

This is a long shot, however I'm trying to infer a universal reference of type std::list<T> for some T.
I have something like this:
// Is the type A the same as B, regardless of const and references
template <typename A, typename B>
struct is_same_kind {
static constexpr auto value = std::is_same_v<std::remove_cv_t<std::remove_reference_t<A>>,
std::remove_cv_t<std::remove_reference_t<B>>>;
};
template <typename A, typename B>
static constexpr auto is_same_kind_v = is_same_kind<A,B>::value;
template<typename L, typename T, typename = std::enable_if_t<is_same_kind_v<L, std::list<T>>>>
T head(L&& l) {
return *std::forward<L>(l).begin();
}
I get an error as the preprocessor is not able to infer T. Maybe there's some nice trick to infer both L&& as universal reference to std::list<T> and the type T from the argument l?
EDIT: Here's how to call it for example:
int main() {
std::cout << head(std::list{1,2,3});
}
I expect to get 1.
Alright, I think I found a way to do this by defaulting to the value_type member. I'm calling remove_reference_t<L> first, as L& :: value_type won't work if it's passed by lvalue reference.
template<typename L, typename T = typename std::remove_reference_t<L>::value_type, typename = std::enable_if_t<is_same_kind_v<L, std::list<T>>>>
T head(L&& l) {
return *std::forward<L>(l).begin();
}
int main() {
std::cout << head(std::list{1,2,3});
}
This is not an answer to your original question, but an important point on the implementation of your function. The way you use the captured value is incorrect. For ints it doesn't matter, because there is nothing to move, but for some types it does matter (especially for those for which L&& makes real sense). For example:
template<typename L>
auto head(L&& l) {
return *std::forward<L>(l).begin();
}
int main() {
std::list<std::unique_ptr<int>> list;
list.push_back(std::make_unique<int>(1));
list.push_back(std::make_unique<int>(2));
auto z = head(std::move(list));
return 0;
}
This code will not even compile. Here one is trying to make a copy of std::unique_ptr because *it is not moved from.
First, there is no much sense in calling begin() on a forwarded value. The only choice a compiler has is to call either begin() or begin() const and this choice does not depend on the value category of l. The resulting iterator is not automatically an std::move_iterator if begin() is called on an rvalue. Second, you should std::move from *it if an rvalue is passed into the function. So, the head(...) function might look like this (using some nice C++17 features):
template<typename L>
auto head(L&& l) {
if constexpr (std::is_rvalue_reference_v<L&&>)
return std::move(*l.begin());
else
return *l.begin();
}
Instead of *l.begin() we could use l.front(). The same arguments still apply.

Remove rvalueness, keep lvalue references (standard type trait available?)

I'm trying to write a function that returns a subset of a variadic argument pack under the form of an std::tuple. The function should ideally have no runtime overhead (no unnecessary copies), and it should allow users to access lvalue references and modify them.
Value types, lvalue references and const lvalue references should be maintained. Temporaries (rvalue references), should be "converted" to value types to avoid creating invalid references (references to temporaries).
Example of desired results:
int lr = 5;
const int& clr = lr;
auto t = make_subpack_tuple(lr, clr, 5);
static_assert(is_same
<
decltype(t),
std::tuple<int&, const int&, int>
>{}, "");
// Ok, modifies lr:
std::get<0>(t) = 10;
// Compile-time error, intended:
// std::get<1>(t) = 20;
// Ok, 5 was moved into the tuple:
std::get<2>(t) = 30;
Example incomplete implementation:
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple
<
some_type_trait<decltype(xs)>...
>
(
std::forward<decltype(xs)>(xs)...
);
}
Does what I am trying to do make sense?
Is there a standard type-trait that can be used in place of some_type_trait? Or should I implement my own solution?
The solution for you will be
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple<Ts...>(std::forward<Ts>(xs)...);
}
According to template argument deduction rules, the parameter pack Ts... will contain only cv-qualified types and lvalues. The information in this question may be useful too.
I'd just like to chime in that I ran into this same not-really-a-problem ("I think I need to decay rvalue references and keep lvalue references untouched") while implementing an efficient version of Nick Athanasios's foldable Op<operation>. I had had this mess:
template<class Pack, class Op>
struct Foldable
{
mystery_trait_t<Pack> value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(static_cast<std::decay_t<Pack>>(
(op.f)(std::move(value), std::move(rhs.value))
));
}
operator mystery_trait_t<Pack> () && {
return std::move(value);
}
};
template<class Pack>
auto NamedOperator::operator()(Pack&& value) const {
return Foldable<Pack, NamedOperator>(std::forward<Pack>(value), *this);
}
and (after puzzling for a bit, and then starting to ask a SO question, and finding this existing question/answer, and adding a static_assert to my implementation of mystery_trait_t to verify that it was never actually invoked with an rvalue reference type!) it turned out that all I actually needed was
template<class Pack, class Op>
struct Foldable
{
Pack value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(
(op.f)(std::move(value), std::move(rhs.value))
);
}
operator Pack () && {
return std::move(value);
}
};
(See my whole code on Wandbox.)
This "answer" of mine doesn't contribute any new information, but I thought it would be useful to share, because it just goes to show that even if you think you're way deep in template metaprogramming and are sure you need this "conditional decay" behavior... you really don't need it!
There might be a corollary general rule that writing any_template<T&&> is always a code smell. In Vittorio's original question, he effectively did that twice, although both times it was hidden by decltype syntax:
some_type_trait<decltype(xs)>... // should have been `Ts...`
std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...`

Accept lvalue ref or rvalue ref

I want to write some functions that take an Object as one of their arguments, whether by lvalue or rvalue ref doesn't matter - but definitely not by value and definitely only an Object. It seems like I have two options for this:
void foo(Object& o) {
// stuff
}
void foo(Object&& o) { foo(o); } // this is fine for my use-case
Or using universal references:
template <typename T, typename U>
using decays_to = typename std::is_same<std::decay_t<T>, U>::type;
template <typename T>
std::enable_if_t<decays_to<T, Object>::value>
foo(T&& o)
{
// same stuff as before
}
But the first option involves writing twice as many functions as I need, and the second option involves writing a bunch of template stuff which is seems like overkill to me (I kind of read that as accept anything for o - oh just kidding, really just an Object).
Is there a better way to solve this or am I just pretty much stuck with whichever one of these I feel less meh about?
There is a difference between your two implementations. The first will admit anything convertible to Object, Object&& or Object&. The second will only admit Object and things that inherit from it in rvalue or lvalue form (and reject const Objects, much like the first).
We can add a helper object:
template<class T>
struct l_or_r_value {
T& t;
l_or_r_value( T&& t_ ):t(t_) {}
l_or_r_value( T& t_ ):t(t_) {}
operator T&(){ return t; }
T* operator->(){ return &t; }
T& operator*(){ return t; }
T& get(){ return t; }
};
then we can write:
void foo(l_or_r_value<Object> o)
and we get behavior that is very close to your second solution, without the template mumbo jumbo at point of call. You do have to access *o and o-> or do a Object& o = o_; to get at the raw reference.
It is not like the first solution, because C++ does not chain two user-defined conversions.
The concepts proposal would add the ability to say "I take anything here, so long as it is an Object" with a more terse syntax.
Another approach would be to just take Object&, and use:
tepmlate<class T>
T& lvalue( T&& t) { return t; }
to convert rvalues to lvalues when you need to (you could also call it unmove to be cute)
The typical way to accept both lvalues and rvalues is to make a function that takes a const reference. That means you can't call non-const functions on the object, but if you want to pass rvalues such as temporaries, then calling non-const functions wouldn't necesarily make much sense anyway.

Is it possible to allow one std::function type accept lambdas with different signatures

I have a higher order function map which is similar to STL for_each, and maps a std::function object over a vector of things.
template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
Now, I want to have this higher order function take both objects of types function<int (const vector<T>&)> and function<int (vector<T>)>, as shown in the attached minimal example.
The problem is that function<int (const vector<T>&)> and function<int (vector<T>)> seem to be convertible to each other (see head and head2), but map won't take the const references version function<int (const vector<int>&)> (see Q1).
It is possible to tell map to accept the const reference version with explicit conversion (Q2), but this is rather cumbersome.
I was wondering if, in general, it is possible to write a function deref that removes the const reference from function<int (const vector<T>&)> and returns a function<int (vector<T>)>?
(If above is possible, then I won't have to write two identical overloads/implementations of map for const refs).
Thanks.
#include <vector>
#include <functional>
using namespace std;
template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
int main() {
vector<vector<int>> m;
function<int (const vector<int>&)> head = [](const vector<int>& a) {return a[0];};
function<int (const vector<int>&)> head1 = [](vector<int> a) {return a[0];}; //conversion OK
function<int (vector<int>)> head2 = [](const vector<int>& a) {return a[0];}; //conversion OK
map(head2,m); //OK
map(head,m); //Q1: problem line, implicit conversion NOT OK
map(function<int (vector<int>)>(head),m); //Q2: explicit conversion OK
map(deref(head),m); //Q3: ??How-to, deref takes a std::function f and returns a function with const ref removed from its signature
return 0;
}
--- EDIT ---
I am particularly interested in a deref like function or a meta-function that can remove the const ref from the type signature of a std::function object, so that I can at least do Q2 automatically.
I know that, as #Brian and #Manu correctly pointed out, the use of std::function to specify types is not conventional, but I wonder what I asked above is even feasible. Personally, I think code with std::function has greater clarity, considering how generic function types Func<T1, T2, T3, ...,Tn, Tresult> are used in C#. This is if the cost of type erasure is tolerable.
I fully agree that c++ can infer return types and give an error message when type is wrong. Maybe it's just a matter of taste and I would prefer to spell it out when writing function signatures.
I understand why you are using std::function: You have to know the return type of the transformation to create the vector, right?
But consider a completely different approach. Given the metafunction std::result_of you could compute the result type of a function call, so just write:
template<typename F , typename CONTAINER , typename T = typename std::result_of<F(typename CONTAINER::value_type)>::type>
std::vector<T> map( F f , CONTAINER&& container )
{
std::vector<T> result;
for( auto& e : container )
result.emplace_back( f( e ) );
return result;
}
Advantages:
No abuse of std::function: Always think what std::function does (i.e. type erasure), don't use it as an universal function type.
Rely on duck typing instead of coupling on the types: Don't worry, if something was wrong it wouldn't compile neither.
Works for any Standard Library Container since we extracted the element type with the value_type trait, instead of using std::vector directly.
The code is much more clear and efficient, both because the reduction of std::function usage.
Regarding the question "Its possible to write a function that accepts lambdas of multiple signatures?"
Using std::function you could write something similar to Boost.OverloadedFunction in a couple of lines:
template<typename F , typename... Fs>
struct overloaded_function : public std_function<F> , public std_function<Fs>...
{
overloaded_function( F&& f , Fs&&... fs ) :
std_function<F>{ f },
std_function<Fs>{ fs }...
{}
};
Where std_function is a metafunction which given a function type F returns the std::function instance with the signature of F. I leave it as a game/challenge for the reader.
Thats all. Improve it with a make-like function:
template<typename F , typename... Fs>
overloaded_function<F,Fs...> make_overloaded_function( F&& f , Fs&&... fs )
{
return { std::forward<F>( f ) , std::forward<Fs>( fs )... };
}
And you are ready to go:
auto f = make_overloaded_function( [](){ return 1; } ,
[](int,int){ return 2; } ,
[](const char*){ return 3; } );
f(); //Returns 1
f(1,2); //Returns 2
f("hello"); //Returns 3
EDIT: "Thanks. But, what I am really looking for, is a meta-function that takes the signature of a callable, and removes the const refs from the signature."
Ok, let me try: The std::decay metafunction applies the decaying done when passing argumments by value to a given type. This includes removing cv qualifiers, removing references, etc. So a metafunction like yours could be something that takes a function signature type and applies decaying to all its argumments:
template<typename F>
struct function_decay;
template<typename R typename... ARGS>
struct function_decay<R(ARGS...)>
{
using type = R(typename std::decay<ARGS>::type...);
};
That should do the work.
I have written this because you explicitly asked for it in the comment, but I strongly encourage you to use the alternative I showed you initially, because it has many advantages compared to your way.
That said, I hope this answer helped to solve your problem.
The idiomatic solution is to simply allow map to take an arbitrary function-like type,
template<class T, class F>
auto map(F f, vector<T> xs) -> vector<typename result_of<F(T)>::type> {
vector<typename result_of<F(T)>::type> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
The main issue with this approach is that you get confusing error messages if F is not callable with arguments of type T, or if it returns something strange, like void.
(A secondary issue is that the first argument to map can't be an overloaded function; the compiler won't simply be able to pick the overload that takes an argument of type T.)
(You might also want to consider decaying the return type of f.)

C++ template to cover const and non-const method

I have a problem with duplication of identical code for const and non-const versions. I can illustrate the problem with some code. Here are two sample visitors, one which modifies the visited objects and one which does not.
struct VisitorRead
{
template <class T>
void operator()(T &t) { std::cin >> t; }
};
struct VisitorWrite
{
template <class T>
void operator()(const T &t) { std::cout << t << "\n"; }
};
Now here is an aggregate object - this has just two data members but my actual code is much more complex:
struct Aggregate
{
int i;
double d;
template <class Visitor>
void operator()(Visitor &v)
{
v(i);
v(d);
}
template <class Visitor>
void operator()(Visitor &v) const
{
v(i);
v(d);
}
};
And a function to demonstrate the above:
static void test()
{
Aggregate a;
a(VisitorRead());
const Aggregate b(a);
b(VisitorWrite());
}
Now, the problem here is the duplication of Aggregate::operator() for const and non-const versions.
Is it somehow possible to avoid duplication of this code?
I have one solution which is this:
template <class Visitor, class Struct>
void visit(Visitor &v, Struct &s)
{
v(s.i);
v(s.i);
}
static void test2()
{
Aggregate a;
visit(VisitorRead(), a);
const Aggregate b(a);
visit(VisitorWrite(), b);
}
This means neither Aggregate::operator() is needed and there is no duplication. But I am not comfortable with the fact that visit() is generic with no mention of type Aggregate.
Is there a better way?
I tend to like simple solutions, so I would go for the free-function approach, possibly adding SFINAE to disable the function for types other than Aggregate:
template <typename Visitor, typename T>
typename std::enable_if< std::is_same<Aggregate,
typename std::remove_const<T>::type
>::value
>::type
visit( Visitor & v, T & s ) { // T can only be Aggregate or Aggregate const
v(s.i);
v(s.d);
}
Where enable_if, is_same and remove_const are actually simple to implement if you don't have a C++0x enabled compiler (or you can borrow them from boost type_traits)
EDIT: While writing the SFINAE approach I realized that there are quite a few problems in providing the plain templated (no SFINAE) solution in the OP, which include the fact that if you need to provide more than one visitable types, the different templates would collide (i.e. they would be as good a match as the others). By providing SFINAE you are actually providing the visit function only for the types that fulfill the condition, transforming the weird SFINAE into an equivalent to:
// pseudocode, [] to mark *optional*
template <typename Visitor>
void visit( Visitor & v, Aggregate [const] & s ) {
v( s.i );
v( s.d );
}
struct Aggregate
{
int i;
double d;
template <class Visitor>
void operator()(Visitor &v)
{
visit(this, v);
}
template <class Visitor>
void operator()(Visitor &v) const
{
visit(this, v);
}
private:
template<typename ThisType, typename Visitor>
static void visit(ThisType *self, Visitor &v) {
v(self->i);
v(self->d);
}
};
OK, so there's still some boilerplate, but no duplication of the code that depends on the actual members of the Aggregate. And unlike the const_cast approach advocated by (e.g.) Scott Meyers to avoid duplication in getters, the compiler will ensure the const-correctness of both public functions.
Since your ultimate implementations are not always identical, I don't think there's a real solution for your perceived "problem".
Let's think about this. We have to cater for the situations where Aggregate is either const or non-const. Surely we should not relax that (e.g. by providing only a non-const version).
Now, the const-version of the operator can only call visitors which take their argument by const-ref (or by value), while the non-constant version can call any visitor.
You might think that you can replace one of the two implementations by the other. To do so, you would always implement the const version in terms of the non-const one, never the other way around. Hypothetically:
void operator()(Visitor & v) { /* #1, real work */ }
void operator()(Visitor & v) const
{
const_cast<Aggregate *>(this)->operator()(v); // #2, delegate
}
But for this to make sense, line #2 requires that the operation is logically non-mutating. This is possible for example in the typical member-access operator, where you provide either a constant or a non-constant reference to some element. But in your situation, you cannot guarantee that the operator()(v) call is non-mutating on *this!
Therefore, your two functions are really rather different, even though they look formally similar. You cannot express one in terms of the other.
Maybe you can see this another way: Your two functions aren't actually the same. In pseudo-code, they are:
void operator()(Visitor & v) {
v( (Aggregate *)->i );
v( (Aggregate *)->d );
}
void operator()(Visitor & v) const {
v( (const Aggregate *)->i );
v( (const Aggregate *)->d );
}
Actually, coming to think of it, perhaps if you're willing to modify the signature a bit, something can be done:
template <bool C = false>
void visit(Visitor & v)
{
typedef typename std::conditional<C, const Aggregate *, Aggregate *>::type this_p;
v(const_cast<this_p>(this)->i);
v(const_cast<this_p>(this)->d);
}
void operator()(Visitor & v) { visit<>(v); }
void operator()(Visitor & v) const { const_cast<Aggregate *>(this)->visit<true>()(v); }
Normally with this type of thing, it's possibly better to use methods that make sense. For example, load() and save(). They say something specific about the operation that is to be carried out via the visitor. Typically both a const and non-const version is provided (for things like accessors anyway), so it only appears to be duplication, but could save you some headache debugging later down the line. If you really wanted a workaround (which I wouldn't advice), is to declare the method const, and all the members mutable.
Add visitor trait to tell whether it's modifying or not (const or non-const use).
This is used by STL iterators.
You could use const_cast and change VisitorRead's method signature so it also take's const T& as a parameter, but I think that is an ugly solution.
Another solution - require the Visitor class to have a metafunction that adds const when it applies:
template <class Visitor>
static void visit(Visitor &v, typename Visitor::ApplyConst<Aggregate>::Type &a)
{
v(a.i);
v(a.d);
}