std::forward and ref-qualifiers for member functions - c++

I was in a position where I was using std::forward wherever I had a forwarding reference and I was wondering if some of that was unnecessary or even wrong. For example having std::forward in a std::begin() call.
Because of the ability of a class being able to overload its member functions based on whether the call is made with the object as an rvalue or not https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/, I assumed that a templated function would be as efficient as possible if you were knew that the inner function you were forwarding the object to was non-mutating and/or was a member function of the object. For example
template <typename Something>
void do_something(Something&& something) {
std::forward<Something>(something).do_something();
auto iter = std::begin(std::forward<Something>(something));
for_each(iter, std::end(std::forward<Something>(something), []() {});
}
I saw this question (When not to use std::forward with r-values?) but it did not address the member function ref-qualifiers and it also did not clearly address what the best practice is when you don't have access to the inner functions definitions that you are calling.
Is there a general guideline for when not to use std::forward that addresses the things I mentioned? Or is there some key concept that I am missing?

Except if you know the type you will have, avoid to use std::forward several time in the same function for the same object, as the second time, your object might be moved.
// assuming implementation which really need pass by value instead of const reference
template <typename T> void pass_by_value(T t) { std::cout << t; }
template <typename T>
void foo(T&& t)
{
pass_by_value(std::forward<T>(t));
pass_by_value(std::forward<T>(t));
}
a call of foo with std::string
foo(std::string("Hello world")); // or "Hello world"s
might call the equivalent to
pass_by_value(std::string("Hello world"));
pass_by_value(std::string("")); // Moved string...

The problem is a use after object moved from ("stealed"). If something used in a multiple lines of do_something, then use std::forward only at the last such line to prevent the problem.

Related

Does Boost (or another library) offer a way to lift the name of a "constructor-less" class into a function object that uses aggregate initialization?

This is kind of a follow up to this question, where I asked how I could tersely turn a template and/or overloaded function into a function object.
The accepted answer was you can't do without macro, which is correct. Then I found that such a macro is offered by Boost, in the form of the BOOST_HOF_LIFT and BOOST_HOF_LIFT_CLASS macros.
It turns out, however, that there are other "named things" you can't pass around. I don't know all of them, but one of them is constructors. And Boost.Hof offers a way to lift them to, via boost::hof::construct.
The point is that not even boost::hof::construct can deal with a class without a user-declared constructor. For intance, given
struct Foo {
int foo;
};
the call boost::hof::construct<Foo>()(3) simply doesn't work. (Adding the constructor Foo(int) {} in Foo makes it work; that's what boost::hof::construct is for, after all.)
Surely, in simple cases like the one above I could just write
auto makeFoo = [](int x){ return Foo{x}; };
but if I want to support any type, I have to take care of perfect forwarding and variadic arguments.
Is there a library offering this feature already? It doesn't look like Boost.Hof does...
If you want a function object that constructs an object of some type T given some parameters, even if T is an aggregate, that's not difficult to write in C++17:
template<typename T>
struct lifted_construct
{
template<typename ...Args>
T operator() (Args&& ...args)
{
if constexpr(std::is_aggregate_v<T>)
{
return T{std::forward<Args>(args)...};
}
else
{
return T(std::forward<Args>(args)...);
}
}
};
Of course, in C++20, you can use () syntax even for aggregates.

How to define a function to work with move semantics and copy semantics?

Suppose that I am implementing a collection and I want to add an element to it, something like.
template <typename T>
class MyCollection
{
void add(const T& element);
};
Now, since adding element usually means copying it, for efficiency reason it makes sense to have the
following version of add as well void add(T&& element). Now the problem is that, obviously the code for both functions is exactly the same, with only difference being the argument type. My command of C++ is limited at the moment, but I would like to know whether there is a simple and idiomatic way to write the addthe function once without rewriting it twice?
In fact this is solved by defining a single overload:
void add(T element) {
where_it_is_actually_stored.insert(std::move(element));
}
Next, depending on whether you're adding a lvalue, a rvalue made from a moved lvalue, or a temporary object, the compiler will resolve an appropriate constructor so your value argument would be either copied or moved.
The most general solution, I think, would actually be this. This is what the standard library provides, so I suppose that makes it "idiomatic".
template<typename T>
struct my_collection {
template<typename... Args>
void emplace(Args&&... args) {
// construct the T object directly in its place out of std::forward<Args>(args)...
}
};

Type erasure and variadic templated member function

The example below is a minimal, maybe not so good example of a well known idiom.
It compiles and it is so ugly in order to be able to maintain it minimal, because the question is not about the idiom itself.
struct Foo {
virtual void fn() = 0;
};
template<class T>
struct Bar: public Foo {
void fn() override {
T{}.fn();
}
};
struct S {
void fn() { }
};
int main() {
Foo *foo = new Bar<S>{};
foo->fn();
}
What I'm struggling with since an hour ago is how to change it (or even, if there exists an alternative idiom) to introduce a variadic template member method.
Obviously, I cannot modify the fn function of the Foo class, because it's a virtual one and virtual specifier doesn't goes along with templates. The same is valid for the fn specification of Bar, because it has to override somehow the one in the base class.
Note.
For I strongly suspect that this question could be one of the greatest XYProblem ever seen, I'd like also to give a brief description of the actual problem.
I have a class that exposes two templated member methods:
the first one accepts a template class T that is not used immediately, instead it should be stored somehow in order to be used later.
the second one accepts a variadic number of arguments (it is actually a variadic templated member function) and those arguments should be perfectly forwarded to a newly created instance of T.
Well, the problem is far more complex, but this is a good approximation of it and should give you an idea of what's the goal.
Edit
I guess that it is somehow similar to higher order functions.
I mean, what would solve the problem is indeed a templated function to which to bind the first argument, but as far as I know this is impossible as well as any other approach I've explored so far.
Any viable solution that expresses the same concept?
What I mentioned in the comments is the following approach:
template<typename T> class Factory {
public:
template<typename ...Args>
auto construct(Args && ...args)
{
return T(std::forward<Args>(args)...);
}
};
So now, your first exposed class method will be something like this:
template<typename T>
auto getFactory() {
return Factory<T>();
}
So:
auto factory=object.getFactory<someClass>();
// Then later:
factory.construct(std::string("Foo"), bar()); // And so on...
Instead of construct() you could use operator() too, so the second part of this becomes, simply:
factory(std::string("Foo"), bar()); // And so on...
As I mentioned, this is not really type erasure. You can't use type erasure here.
Having given this a few minutes' more thought, the reason that type erasure cannot be used here is because a given instance of type erasure must be "self contained", or atomic, and what you need to do is to break atomic type erasure into two parts, or two class methods, in your case.
That won't work. Type erasure, by definition, takes a type and "erases" it. Once your first function type-erases its class method template parameter, what you end up with is an opaque, type-erased object of some kind. What was type-erased is no longer available, to the outside world. But you still haven't type-erased your constructor parameters, which occurs somewhere else.
You can type-erase the template class, and the constructor parameters together. You can't type-erase the template class, and the constructor parameters, separately and then somehow type-erase the result again.
The simple factory-based approach, like the one I've outlined, would be the closest you can get to results that are similar to type erasure, if both halfs of your desired type-erasure appear in the same scope, so you can actually avoid type-erasure, and instead rely on compiler-generated bloat.
I also agree that you cannot do exactly what you want here. I will post what I think the closest option is (at least a close option that is different from SamVarshavchik's answer).
I don't expect this answer to solve your problem exactly, but hopefully it will give you some ideas.
struct Delay // I have no idea what to call this
{
template <class T>
void SetT()
{
function_ = [](boost::any params){return T(params);}
}
template <class ... Args>
boost::any GetT(Args ... args)
{
return function_(std::make_tuple(args...));
}
private:
std::function<boost::any(boost::any)> function_;
};
The obvious limitation of this is that anyone calling GetT will somehow have to know what T was already, though you can query the boost::any object for the type_info of its class if that helps. The other limitation here is that you have to pass in T's that take a boost::any object and know what to do with it. If you cannot have T do that, then you can change SetT (or create a new member function) like this:
template <class F>
SetTFactory(F f)
{
function_ = f;
}
and then use it like:
Delay d;
d.SetTFactory([](boost::any s){return std::string(boost::any_cast<const char*>(s));});
auto s = d.GetT("Message");
assert(s.type() == typeid(std::string));
This of course introduces a whole new set of difficulties to deal with, so I don't know how viable this solution will be for you. I think regardless of anything else, you're going to have to rethink your design quite a bit.

Replacing template function foo(T*) by foo(T)

In my code, I have a function:
template<typename T>
void foo (T*); // make sure that 'foo()' is passed only pointers
Now in new implementation, I am passing also a smart pointer (something like shared_ptr<>. So I have changed the signature of the function to,
template<typename T>
void foo (T); // pointers or smart-pointers
The code shall work fine. However, is there any side effect I am missing ?
You could use enable_if to only allow pointers or instances of shared_ptr to compile if you want. That way you can get back the compile-time checking you had before (though, presumably, your functions implementation would do that as well).
void foo(T) is pass-by-copy.
T& (pass by reference) would be more efficient if sizeof(T) is non-small.

How do you pass boost::bind objects to a function?

I have a one-dimensional function minimizer. Right now I'm passing it function pointers. However many functions have multiple parameters, some of which are held fixed. I have implemented this using functors like so
template <class T>
minimize(T &f) {
}
Functor f(param1, param2);
minimize<Functor>(f);
However the functor definition has lots of crud. Boost::bind looks cleaner. So that I could do:
minimize(boost:bind(f,_1,param1,param2))
However I'm not clear what my minimize declaration should like like using boost::bind. What type of object is boost::bind? Is there an easy pattern for this that avoids the boilerplate of functors but allows multiple parameter binding?
You can just use boost::function. I think boost::bind does have its own return type, but that is compatible with boost::function. Typical use is to make a typedef for the function:
typedef boost::function<bool(std::string)> MyTestFunction;
and then you can pass any compatible function with boost::bind:
bool SomeFunction(int i, std::string s) { return true; }
MyTestFunction f = boost::bind(SomeFunction, 42, _1);
f("and then call it.");
I hope that is what you want.
It also works with methods by passing the this pointer for the call as second parameter to boost::bind.
I would define minimize() this way:
minimize(boost::function< return_type(param_type1,param_type2,param_type3,...)> f)
{
...
}
Then you could call minimize() like this:
minimize(boost::bind(&class::function,actual_object,_1,_2,_3,...));
Change the parameter to a value parameter. Function objects are intentionally light weight, and boost::bind certainly is, specially crafted to fit in within space of a few bytes using boost::compressed_pair and what not.
template <class T>
void minimize(T f) {
}
Then you can pass it the result of boost::bind. Remember that boost::bind is actually a function template that returns some object of some type. So having minimize have a non-const reference parameter couldn't work.
First, you are taking your template argument as a ref-to-non-const, so the temporary returend by boost::bind won't bind to it. So you can use it like:
template <class T>
T::result_type minimize(const T &f) {
}
But if you wanted to use this with your Functors as well, they would have to have a const operator(). So perhaps by value is better:
template <class T>
T::result_type minimize(T f) {
}
I believe having the return be T::result_type will force a T to be a boost::function (rather than the complicated type bind returns), but I'm not 100%