Assume you are providing a client library with a function that has multiple reference arguments.
For the sake of simplicity lets assume we have 3 arguments and those are various references to int (so you can assume, that these constants would also be created by initializer_list).
From a call site it should be possible to pass ad hoc created constants (rvalue) to functions (think of testing code in this case) as well as real references to objects being owned by another entity.
So far I've come up with the following solutions:
void bar(int &x, int &y, int &z) { }
// use a template wrapper to turn rvalues into lvalues.
template <typename T, typename U, typename V>
void foo(T &&t, U &&u, V &&v) {
bar(t,u,v);
}
// create a humongous amount of overloads
void baz(int &&x, int &y, int &z) { }
void baz(int &x, int &&y, int &z) { }
void baz(int &&x, int &&y, int &z) { }
void baz(int &x, int &y, int &&z) { }
void baz(int &&x, int &y, int &&z) { }
void baz(int &x, int &&y, int &&z) { }
void baz(int &&x, int &&y, int &&z) { }
// claim ownership of the objects and create temporaries
void bam(int x, int y, int z) { }
int main() {
int i = 1;
foo(i,2,3);
foo(2,i,3);
foo(2,3,i);
bar(i,2,3); // doesn't compile
bar(2,i,3);
bar(2,3,i);
baz(i,2,3); // requires 8 overloads
baz(2,i,3);
baz(2,3,i);
return 0;
}
I'm not completely satisfied with all of the solutions as every one of them has drawbacks. Is there a cleaner alternative to this problem?
This question is actually not trivial but there some guidelines that have evolved over the years and have actually not changed too much with C++11. For the following we will assume that you have a side-effect free, free-standing function (guidelines are slightly different for constructors and certain member functions).
What I would recommend for a free-standing function is:
Pass primitive data types (int, double, bool, etc.) by value
Pass complex data types by const reference (e.g. const std::vector&) unless you need a copy within the function then pass by value
If your function is templated use const reference (e.g. const T&) since both lvalue and rvalue will bind to const references
If your function is templated and you intend to perfect forward then use forwarding references (e.g. T&&, also called universal references)
So for your example using integers I would use the bam function:
void bam(int x, int y, int z) { }
There is an interesting talk by Herb Sutter given at the CppCon last year that
among other stuff covers input arguments to functions:
https://www.youtube.com/watch?v=xnqTKD8uD64
Another interesting post on stackoverflow related to this question:
Correct usage of rvalue references as parameters
Update for constructors:
The main difference for constructors to the recommendations above is a stronger emphasis on copying input and making the object owned by the class. The same holds for setters. The main reason is safer resource management (to avoid data races or accessing invalid memory).
This is the perfect forwarding problem. The way you avoid the 8 overloads of baz is to use the so-called universal references:
template <typename T, typename U, typename V>
void baz(T &&t, U &&u, V &&v) { }
In the above, t, u and v faithfully replicate the r/l-valueness for the parameters. For example, say your original intended function was this:
void baz(vector<int> &t, vector<int> &u, vector<int> &v) { }
and the other 7 overloads. With the templated version, if you call baz(a,b,c) where a and b are rvalues, while c isn't, T and U will be deduced to be vector<int>&& while V will be deduced to be vector<int>&. Thus, you have all the information you need in this implementation.
template<class T>
struct lrvalue {
T&t;
lrvalue(T&in):t(in){}
lrvalue(T&&in):t(in){}
};
take lrvalue<int>. Problem solved? You can dress them up, maybe inherit from reference_wrapper or somesuch instead of T&t.
You can also cast when calling:
template<class T>
T& lvalue(T&&t){return t;}
template<class T>
T& lvalue(T&t)=delete;//optional
now if you want to pass foo{} to foo& you can. lvalue(foo{}).
Related
I am struggling to understand how this code even compile when passing a "callable" struct/class.
Referring to the main function below, I would expect the compiler to tell me that there is no matching constructor for Point3D (CallableI is not an instance of FuncType).
What I would be tempting to do is to create an algo member inside CallableI and constructs the point referring to it. But this solution is better on many aspect so I want to understand how it is working under the hood.
I have a base class Point3D :
template<typename T>
class Point3D
{
typedef std::function<T (const Point3D<T> &p1, const Point3D<T> &p2)> FuncType;
private:
T x;
T y;
T z;
FuncType algo;
public:
Point3D(T x, T y, T z, FuncType algo) : x(x), y(y), z(z), algo(algo){}
T First() const {return x;}
T Second() const {return y;}
T Third() const {return z;}
T computeDistance(Point3D<T> &p2){
return algo(*this, p2);
}
};
I am using a struct CallableI to hold a particular function to be called overloading operator ().
struct CallableI
{
CallableI(){};
double operator() (const Point3D<double> &p1, const Point3D<double> &p2){
double x1{p1.First()}; double x2{p2.First()};
double y1{p1.Second()}; double y2{p2.Second()};
return std::abs(x1 - x2) + std::abs(y1 - y2);
}
};
And I am calling the suggested code with the main function below :
int main(int argc, char **argv) {
CallableI myCallable;
Point3D<double> p1(14.3, 12.3, 2.0, myCallable);
return 0;
std::function is a type erasure template.
std::function<R(Arg0, Arg1)> is a type erasure type.
It can be constructed with any value that you can:
Invoke with () with Arg0, Arg1 and the return type can be converted to R
Can be copied, moved, and destroyed.
It is a kind of polymorphism that does not require inheritance.
Your CallballI fullfills the requirement, and the constructor of function<double(Point3D<double> const&,Point3D<double> const&)> does the work to make it work.
How type erasure in C++ works is a more advanced subject. In std::function, how it works is unspecified; the standard just says it works. You can implement it yourself through a number of ways (which in turn could use inheritance), but at this point in your learning C++ I'd advise against it.
The core idea is that C++ templates are ridiculously powerful, and std::function has a template constructor that write the glue code that lets you store an object of unknown but compatible type, and writes the code to invoke (Point3D<double>, Point3D<double>) on it.
template<class Sig>
struct function_view;
template<class R, class...Args>
struct function_view<R(Args...)> {
void* pstate = nullptr;
R(*pf)(void*, Args&&...) = nullptr;
R operator()(Args... args) const {
return pf(pstate, std::forward<Args>(args)...);
}
template<class T>
function_view( T&& in ):
pstate( (void*)std::addressof(in) ),
pf( [](void* pvoid, Args&&...args )->R {
return (*decltype(std::addressof(in))(pvoid))( std::forward<Args>(args)... );
})
{}
};
that is an incomplete (simplified in a number of ways) sketch of a semi-useful non-owning function view. This is not the only way to do type erasure in C++, just one that is brutal, simple and short.
The core is that function_view<Sig> knows what it needs, it saves what how to do it when constructed and then forgets everything else about the type passed (it "erases" it from its memory).
Then it uses those saved operations on the type erased data when you ask for it to do its operation.
Live example.
Here,
void foo( function_view<int(int)> f ) {
std::cout << f(3);
}
foo isn't a template, but can accept any unrelated type that supports calling with int and returns something that can convert to int.
In this interview Stepanov shows how to implement generic max function in C++.
Try to implement a simple thing in the object oriented way, say, max.
I do not know how it can be done. Using generic programming I can
write:
template <class StrictWeakOrdered>
inline StrictWeakOrdered& max(StrictWeakOrdered& x,
StrictWeakOrdered& y) {
return x < y ? y : x;
}
and
template <class StrictWeakOrdered>
inline const StrictWeakOrdered& max(const StrictWeakOrdered& x,
const StrictWeakOrdered& y) {
return x < y ? y : x;
}
(you do need both & and const &).
Why is there need to write the code twice? Is this needed to aid compiler for optimization or a convention to reduce bugs? Is max a special case where body of a const version is identical?
How many valid const and non-const permutations a function of N arguments should have to define a complete API?
First of all, you need the non-const version to allow stuff like
max(a, b) = something;
If you don't want to do such things, you can just provide the const version only to cover all cases. That is basically what the standard std::max does.
You also do not need to provide any more permutations of const and non-const, returning non-const& only makes sense if all inputs are non-const, all other cases are properly handled by the const version.
If you want to avoid code duplication, you can do something like this:
template <class StrictWeakOrdered>
inline StrictWeakOrdered& max(StrictWeakOrdered& x, StrictWeakOrdered& y) {
const auto &xr = x;
const auto &yr = y;
return const_cast<StrictWeakOrdered&>(max(xr, yr));
}
In this special case, the const_cast is safe because you already know that the input is really non-const. Now you only have to provide the implementation for the const case.
So providing the implementation twice is not required and should not help the compiler, but whether or not the above is more readable than what Stepanov did is debatable.
You actually don't need both versions. You can write it this way.
template <class S, class T>
decltype(auto) max(S&& a, T&& b) {
using Ret = std::conditional_t<
std::is_const<std::remove_reference_t<S>>::value, S, T>;
if (b < a)
return std::forward<Ret>(a);
return std::forward<Ret>(b);
}
Falling back to const if either of the arguments was const.
If you do not intend to modify the argument, you can just go with the const& version. Everything should bind to a const reference.
C++11 also introduced reference collapsing, and a template parameter T&& is sometimes called a universal reference. In this case, when instantiating the parameter type for e.g. a int&, we would have int& && which collapses to int&. Now, you can write the function as
template <class T1, class T2>
inline T1 const& max(T1&& x, T2&& y) {
T1 const& x_=x;
T2 const& y_=y;
return (x_ < y_) ? (y_) : (x_);
}
This can be called with const values, temporaries (r-values) and mutable variables:
int const a=1;
int b=2;
max(b,b) = 23;
std::cout << max(a,a) << max( int{4}, int{5} ) << b << max(int{4}, a);
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! :)
Suppose I have a template function foo() that takes two integer references as parameters. I'd like the template function to also automatically handle constant references (such as those from constants). Here is a generalized example. I can get foo() to work, but I have to provide a new implementation for every permutation of reference/const-reference parameters.
#include <iostream>
using namespace std;
template<typename A, typename B>
void foo(A& a, B& b)
{
cout<<"a:"<<a<<" b:"<<b<<endl;
}
template<typename A, typename B>
void foo(A& a, const B& b)
{
cout<<"a:"<<a<<" b:"<<b<<endl;
}
template<typename A, typename B>
void foo(const A& a, B& b)
{
cout<<"a:"<<a<<" b:"<<b<<endl;
}
template<typename A, typename B>
void foo(const A& a, const B& b)
{
cout<<"a:"<<a<<" b:"<<b<<endl;
}
int main()
{
int x = 0;
foo(x, x);
foo(x, 10);
foo(10, x);
foo(20, 20);
return 0;
}
The above example is a little bit contrived, but it is a generalization of what I am trying to do. In my more complex case, I have a class that acts as a wrapper to a set of parameters. The class constructor is templated, like foo(), and can have as many as 10 parameters. It would be a nightmare to enumerate all 2^10 possible constructors.
The problem that you describe is perfect forwarding problem. C++11 solved this problem with universal references:
template<typename A, typename B>
void foo(A&& a, B&& b) {
bar(std::forward<A>(a), std::forward<B>(b));
}
Parameters here are not rvalue references, but universal references. They will have the same ref-ness and const-ness as arguments.
If arguments are rvalues, in foo parameters will be rvalues with names. Named rvalues are lvalues. To pass parameters to sub-functions with preserved value-ness, you need to wrap them in std::forward. Function bar will get a and b with exactly the same type as foo.
If the template is not going to modify the arguments, then just offer the version with the const& and you should be fine:
template<typename A, typename B>
void foo(const A& a, const B& b)
{
cout<<"a:"<<a<<" b:"<<b<<endl;
}
If you pass a non-const lvalue, it will still be bound by a const reference and everything will work.
If you want some of the overloads to modify the arguments, then rethink the design, as those don't seem like functions that should share a name. There are exceptions, for examples, accessors into internal members of a structure, where you might want to return a const& if the object is const or a non-const reference otherwise... If that is the case, you can go the opposite way and offer only the non-const overload:
template<typename A, typename B>
void foo(A& a, B& b)
In this case, if the argument is a temporary or a non-const reference, the deduce type will reflect it and it will bind the argument with a const&.
int main() {
int a = 5;
const int b = 10;
foo(a,b); // foo<int,const int>(int&,const int&)
foo(10,b); // foo<const int,const int>(const int&, const int&)
}
Rereading your question it seems that you might be interested in perfect forwarding (this might or not fit your bill). If that is the case, and if you have a C++11 compiler you can use universal-references with a variadic template. Building a good wrapper is a hard thing, although you might be able to just use std::tuple as the actual storage, which should make the task quite simple.
Apart from all the answers posted which are correct, here is a simple program just for your reference as this might help you to understand the concept better.
#include<iostream>
template<class X>
void func(X& x, X& y)
{
//your code
}
template<class X, class Y>
void intermediateFunc(X&& x, Y&& y)
{
func(x,y);
}
int main()
{
int y = 9;
intermediateFunc(5,5);
intermediateFunc(y,5);
intermediateFunc(5,y);
intermediateFunc(y,y);
}
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);
}