Consider following code sample:
template<class T, class U>
struct b{
b(T &&, U &&);
//some useful stuff
};
template<class T>
struct factory{
factory(T &&arg) : arg_(std::forward<T>(arg)){}
template<class U>
auto create(U &&u) const &{
return b<const T &, U>(arg_, std::forward<U>(u));
}
template<class U>
auto create(U &&u) &&{
return b<T, U>(std::forward<T>(arg_), std::forward<U>(u));
}
T arg_;
};
template<class T>
auto
make_factory(T &&t){
return factory<T>(std::forward<T>(t));
}
I am concerned with code inside factory struct - are the create methods fastest possible, is it the best way to use perfect forwarding with factory classes?
Did I miss something or this code is 'perfect' in terms of forwarding/moving data around? I would like to avoid copying wherever it is possible.
Should I add/remove const in any of the create methods?
EDIT: Due to Your concerns - I am aware that sometimes I will pass lvalue reference and specialize template for it. It is desired behaviour. As I written up there - I want to avoid copying anything unless really needed. So factory can store reference if object was created in scope outside of it. I know it is unsafe, but still it is a design choice. For reference factory created object should also store reference. I hope this clarifies most of Your issues.
I don't know whether you fully understand what you are doing in the code.
template<class T>
auto
make_factory(T &&t){
return factory<T>(std::forward<T>(t));
}
This code try to make a factory of T. However, if you pass an lvalue to make_factory(), T will be deduced to a reference. Then you will create a factory of reference. I think this is unlikely your purpose.
And moreover, this one
factory(T &&arg) : arg_(std::forward<T>(arg)){}
is not a forwarding reference, because T is not the type name to be deduced in this function.
Related
Reading about universal references led me to wonder: how can I construct a class template such that it stores by reference if possible, or by value if it must?
That is, can I do something like this
template <class T>
class holder {
T obj_m; // should be a reference if possible...
public:
holder(T t) :obj_m { t } {}
}
auto
hold_this(T && t) { return holder<T>(t); }
Except that when hold_this() is given an lvalue the holder will hold a reference, and when given an rvalue the holder will make a copy?
Except that when hold_this() is given an lvalue the holder will hold a reference, and when given an rvalue the holder will make a copy?
You already wrote it (minus the required template <typename T>). The deduction rules for a forwarding reference preserve value category as follows:
If t is bound to an lvalue of type T2, then T = T2&.
If t is bound to an rvalue of type T2, then T = T2.
It's those deduction rules that std::forward relies on to do its job. And why we need to pass the type to it as well.
The above means that you instantiate holder directly with T2 in the rvalue case. Giving you exactly what you want. A copy is made.
As a matter of fact, two copies are made. Once to create the constructor argument t, and the other copy is to initialize obj_m from it. But we can get rid of it with some clever use of type_traits:
template <class T>
class holder {
T obj_m; // should be a reference if possible...
public:
holder(std::add_rvalue_reference_t<T> t) :obj_m { std::forward<T>(t) } {}
};
template<typename T>
auto hold_this(T && t) { return holder<T>(std::forward<T>(t)); }
See it live. We use add_rvalue_reference_t to make t be of the correct reference type in each case. And "simulate" the argument deduction which would make obj_m { std::forward<T>(t) } resolve to initializing obj_m from the correct reference type.
I say "simulate" because it's important to understand the constructor argument for holder cannot be a forwarding reference because the constructor itself is not templated.
By the way, since you tagged c++17, we can also add a deduction guide to your example. If we define it as follows (with the feedback from T.C. incorporated):
template <class T>
class holder {
T obj_m; // should be a reference if possible...
public:
holder(T&& t) :obj_m { std::forward<T>(t) } {}
};
template<typename T>
holder(T&&) -> holder<T>;
Then this live example shows you can define variables as hold h1{t}; and hold h2{test()};, with the same deduced types as the function return values from before.
Imagine some function (RetrieveResult), returning an object by pointer/reference/value - I don't know and don't want to know, because things may change. I just want to store the result, using auto and also protect that object from accidental changing in the current scope or, for example, if the object is propagated upwards.
It is quite intuitive just to write:
const auto result = RetrieveResult();
and everything works fine, if RetrieveResult returns an object by value or by reference. But if the function returns a pointer, constancy is applied to that pointer, not to the object the poiter points to. What way I still can change the object. Writing
const auto const result = ....
results in the compilation error:
duplicate 'const'
Of course, I can declare variable like this:
const auto* ...
const auto* const...
But that way ties me close to pointers, i.e. it isn't a universal solution.
Is it possible to preserve true constancy, and, in the same time, provide flexibility (independency of the concrete type)?
There is experimental support for this utility called std::propagate_const in the Library Fundamentals v2. You can write a type trait on top of that that does this for you (if you do not have std::propagate_const you can consider writing it yourself :))
namespace {
template <typename T, typename = std::enable_if_t<true>>
PropagateConst {
using type = T;
};
template <typename T>
PropagateConst<T, std::enable_if_t<std::is_same<
decltype(*std::declval<std::decay_t<T>>()),
decltype(*std::declval<std::decay_t<T>>())>::value>> {
using type = std::propagate_const_t<std::decay_t<T>>;
};
template <typename T>
using PropagateConst_t = typename PropagateConst<T>::type;
template <typename Type>
decltype(auto) propagate_const(Type&& in) {
return PropagateConst_t<std::add_rvalue_reference_t<Type>>{in};
}
} // <anonymous>
// then use it like this
const auto result = propagate_const(RetrieveResult());
Note that the solution I have above only checks for the presence of an operator* in the possible pointer type. You might want to consider writing a more extensive test for that.
Also note that this uses reference collapsing in the propagate_const example so expect at least a move to happen in cases where you might be expecting elision. You can optimize it based on your use case. I just thought I would outline what was in my head. Maybe that would help
template<class T>
struct very_const_t { using type=T; };
template<class T>
struct very_const_t<T*> { using type=typename very_const_t<T>::type const*; };
template<class T>
struct very_const_t<T&> { using type=typename very_const_t<T>::type const&; };
template<class T>
typename very_const_t<T>::type&&
very_const( T&& t ) { return std::forward<T>(t); }
then:
const auto result = very_const(RetrieveResult());
note that this can block elision. I carefully do not block move semantics, however.
This does not move const into smart pointers. If you want that:
template<class T, class D>
struct very_const_t<std::unique_ptr<T,D>> { using type=std::unique_ptr<typename very_const_t<T>::type const, D>; };
template<class T>
struct very_const_t<std::shared_ptr<T>> { using type=std::shared_ptr<typename very_const_t<T>::type const>; };
will do it for unique and shared.
Consider some function:
template<typename F>
void foo(F f) {
std::unique_ptr<int> p = f();
// do some stuff with p
}
Because unique_ptr decrees a default template argument, default_delete, for D, any function object passed to foo that returns a unique_ptr with a non-default deleter fails to compile. For example,
int x = 3;
foo([&x](){
// use empty deleter
return std::unique_ptr<int>(&x, [](int*){});
});
However, I could see this being potentially useful, and I don't see a direct reason why it shouldn't be possible. Is there a common approach for addressing this?
Edit
The easy fix would be to define foo instead to use the following:
std::unique_ptr<int, std::function<void(int*)>> p = f();
But I'm wondering why this couldn't have been incorporated into the interface for unique_ptr? Is there a reason the class interface couldn't provide this generic attribute? Are there approaches for "wrapping" this kind of thing into a new definition?
For example,
template<typename T>
using Generic_unique_ptr =
std::unique_ptr<
T,
std::function< void(typename std::unique_ptr<T>::element_type*) >
>;
But this seems dangerous because it exposes the potential to do something like the follwing,
Generic_unique_ptr<int> p(new int());
which would leave the deleter uninitialized and exhibit undefined behavior. Perhaps some way to provide an instance of std::default_delete<T> as the default deleter?
If all you want to do is use the pointer in a function, you can just
use the auto keyword; the compiler will deduce the type of unique_ptr
which has been used and thus automatically do the right thing:
template <typename F>
void foo(F f)
{
auto p = f();
p->bar();
}
Now, from your comment, we know that this is not all you want, but you
want to be able to store the unique_ptr in your class to work with
it later. This creates a set of completely different problems:
unique_ptr<T, D1> and unique_ptr<T, D2> are different types. Thus we need to know what unique_ptr<T, D> will be returned by your functor F
Even if we knew the return type of F in advance, our class can still only store unique_ptr<T, D1> and not unique_ptr<T, D2>.
The easiest way around this (that I can think of, there might be better
ways) is type erasure.
We create ourselves a base class that exposes the pointer managed by the
unique_ptr:
template <typename T>
struct wrapper
{
virtual ~wrapper() {}
virtual T const * get() const = 0;
virtual T * get() = 0;
};
From that class inherits our actual storage class, which deduces the type
of unique_ptr:
template <typename T, typename F>
struct storage
: wrapper<T>
{
storage(F f) { p_ = f(); }
T const * get() const { return p_.get(); }
T * get() { return p_.get(); }
private:
typename std::result_of<F()>::type p_;
};
In the class you actually care about, you can now store a pointer to our
base class and use polymorphism to access the underlying object, in this
case the unique_ptr. Assume we moved the classes above into
namespace detail to hide them from the user:
template <typename T>
class some_class
{
public:
template <typename F>
void store(F f)
{
storage_.reset(new detail::storage<T, F>(f));
}
T const * get() const { return storage_->get(); }
T * get() { return storage_->get(); }
private:
std::unique_ptr<detail::wrapper<T>> storage_;
};
You can find a fully working example here.
But I'm wondering why this couldn't have been incorporated into the interface for unique_ptr?
Because to do so would force all of std::function's overhead onto everyone. unique_ptr is intended to be useful for pretty much any case of single ownership of a pointer. You pay for what you use; not everyone who uses a custom deleter needs that deleter to be generic. This way, they don't have to pay for it.
Also, the current methodology allows it to handle non-pointer resources, as the deleter can specify exactly what type gets stored in the unique_ptr.
If you want to provide this generic deleter construct, you could create a class that (privately) inherits from unique_ptr and replicates its interface, minus the constructor that doesn't take a deleter instance. That way, the user is forced to pass a deleter function in.
Among the many benefits of const qualification is to make an API more understandable, example:
template<typename T> int function1(T const& in);
// clearly, the input won’t change through function1
With the introduction of rvalue references, one can benefit from perfect forwarding but often const qualifiers are removed, example:
template<typename T> int function2(T&& in);
// can explicitly forward the input if it's an rvalue
Apart from documentation, is there a good way to describe that function2 won’t change its input?
template<typename T> int function2(T&& in);
// can explicitly forward the input if it's an rvalue
Apart from documentation, is there a good way to describe that
function2 won’t change its input?
Yes. Stick with the C++03 solution:
template<typename T> int function1(T const& in);
// clearly, the input won’t change through function1
The benefits of perfect forwarding are that you don't want to assume if something is const or non-const, lvalue or rvalue. If you want to enforce that something is not modified (i.e. that it is const), then explicitly say so by adding const.
You could do this:
template<typename T> int function1(T const&& in);
// clearly, the input won’t change through function1
However everyone who read your code would wonder why you've used rvalue references. And function1 would cease to accept lvalues. Just use const & instead and everyone will understand. It is a simple and well understood idiom.
You don't want to perfectly forward. You want to enforce immutability.
You could say this:
template <typename T>
typename std::enable_if<immutable<T>::value, int>::type
function(T && in)
{
// ...
}
where you have something like:
template <typename T> struct immutable
: std::integral_constant<bool, !std::is_reference<T>::value> {};
template <typename U> struct immutable<U const &>
: std::true_type {};
This way, the template will only be usable if the universal reference is either a const-reference (so T = U const &) or an rvalue-reference (so T is not a reference).
That said, if the argument is not going to be changed, you could just use T const & and be done with it, since there's nothing to be gained from binding mutably to temporary values.
I'm trying to use decltype in the late specified return of a member function in a CRTP base class and it's erroring with: invalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >.
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
explicit AnyOp(Functor func) : func_(func) {}
template<class Foo>
bool call_with_foo(const Foo &foo) const
{
//do whatever
}
private:
Functor func_;
};
I'm basically trying to move all of the sfinae boiler plate into a base class so I don't need to repeat it for every Operation that I create (currently each operation has 6 different calls and there are ~50 operations so there is quite a lot of repetition with the enable_if's).
I've tried a solution which relied on overloading but one of the types which may be passed is anything that's callable(this can be a regular functor from C++03 or a C++0x lambda) which I bound to a std::function, unfortunately, the overhead from std::function, although very minimal, actually makes a difference in this application.
Is there a way to fix what I currently have or is there a better solution all together to solve this problem?
Thanks.
You are, as another answer describes already, trying to access a member of a class in one of the class' base class. That's going to fail because the member is yet undeclared at that point.
When it instantiates the base class, it instantiates all its member declarations, so it needs to know the return type. You can make the return type be dependent on Foo, which makes it delay the computation of the return type until Foo is known. This would change the base class like the following
// ignore<T, U> == identity<T>
template<typename T, typename Ignore>
struct ignore { typedef T type; };
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
This artificially makes the static_cast cast to a type dependent on Foo, so it does not immediately require a complete Op type. Rather, the type needs to be complete when operator() is instantiated with the respective template argument.
You are trying to refer to a member of a class from one of its own base classes, which will fail since the class's body doesn't exist within its base class. Can you pass the logic for computing the return type of call_with_foo as a metafunction to the base class? Is that logic ever going to be complicated?
Another option, depending on how much flexibility you have in changing your class hierarchy (and remember that you have template typedefs), is to have the wrapper inherit from the implementation class rather than the other way around. For example, you can write a AddParensWrapper<T> that inherits from T and has operator() that forwards to T::call_with_foo. That will fix the dependency problem.