I came across this question, where the answer describes nice detail about how can the generic lambda functions be used to replace the std::function technique and how to rewire the stop condition to enable the return type deduction.
Based on the above I created the following working example:
#include <cstdio>
void printSeq(unsigned start) {
auto recursion = [](auto&& self, const char* format, unsigned current) {
printf(format, current);
if(!current)
return static_cast<void>(printf("\n"));
else
self(self, ", %u", current - 1);
};
recursion(recursion, "%u", start);
}
int main() {
return (printSeq(15), 0);
}
My question is that what's the advantage using auto&& over the auto& in this case? Should I use the std::move here?
auto& is lvalue only.
This matters little until you refactor and replace the lvalue recursive object with a temporary proxy memoizer, for example.
auto&& is harmless, and means "I do not mind if this is a temprary or whatever, just don't make a copy", which expresses meaning well here. auto& states "No temporaries allowed!" Sometimes you want to exclude temporaries when making a reference, but it is rare.
auto const&, auto and auto&& should be your bread and butter.
Only use auto& if your operation is explicitly about writing and you are ok with excluding proxy references.
Related
I have the following code:
#include <variant>
#include <string>
#include <iostream>
using Variant = std::variant<double, std::string>;
// helper type for the visitor
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
std::string string_from(const Variant& v)
{
return std::visit(overloaded {
[](const double arg) { return std::to_string(arg); },
[](const std::string& arg) { return arg; },
}, v);
}
int main()
{
Variant v1 {"Hello"};
Variant v2 {1.23};
std::cout << string_from(v1) << '\n';
std::cout << string_from(v2) << '\n';
return 0;
}
I have a function called string_from() which takes a variant and converts its inner value to a string.
The variant can hold either a std::string or a double.
In case of a std::string, I just return it.
In case of a double, I create a std::string from the double and then return it.
The problem is, I don't like the fact that I'm returning a copy of the std::string in case of a string-variant. Ideally, I would return a std::string_view or another kind of string observer.
However, I cannot return a std::string_view because in case of a double-variant I need to create a new temporary std::string and std::string_view is non-owning.
I cannot return a std::string& for the same reason.
I'm wondering if there's a way to optimize the code so that I can avoid the copy in case of a string-variant.
Note in my actual use case, I obtain strings from string-variants very frequently, but very rarely from double-variants.
But I still want to be able to obtain a std::string from a double-variant.
Also, in my actual use case, I usually just observe the string, so I don't really need the copy every time. std::string_view or some other string-observer would be perfect in this case, but it is impossible due to the reasons above.
I've considered several possible solutions, but I don't like any of them:
return a char* instead of a std::string and allocate the c-string somewhere on the heap in case of a double. In this case, I would also need to wrap the whole thing in a class which owns the heap-allocated strings to avoid memory leaks.
return a std::unique_ptr<std::string> with a custom deleter which would cleanup the heap-allocated strings, but would do nothing in case the string resides in the variant. Not sure how this custom deleter would be implemented.
Change the variant so it holds a std::shared_ptr<std::string> instead. Then when I need a string from the string-variant I just return a copy of the shared_ptr and when I need a string from the double-variant I call std::make_shared().
The third solution has an inherent problem: the std::string no longer resides in the variant, which means chasing pointers and losing performance.
Can you propose any other solutions to this problem? Something which performs better than copying a std::string every time I call the function.
You can return a proxy object. (this is like your unique_ptr method)
struct view_as_string{
view_as_string(const std::variant<double, std::string>& v){
auto s = std::get_if<std::string>(&v);
if(s) ref = s;
else temp = std::to_string(std::get<double>(v));
}
const std::string& data(){return ref?*ref:temp;}
const std::string* ref = nullptr;
std::string temp;
};
Use
int main()
{
std::variant<double, std::string> v1 {"Hello"};
std::variant<double, std::string> v2 {1.23};
std::cout << view_as_string(v1).data() << '\n';
view_as_string v2s(v2);
std::cout << v2s.data() << '\n';
}
The problem is, a variant holds different types, but you're trying to find a way to represent all of them in a single type. A string representation is useful for generic logging, but it has the downsides you describe.
For variants, I don't like trying to consolidate the values back into a single common thing, because if that was easily possible then there would be no need for the variant in the first place.
Better, I think, is to defer the conversion as late as possible, and keep forwarding it on to other functions that make use of the value as it is, or convert and forward until it's used--rather than trying to extract a single value and trying to use that.
A fairly generic function might look like this:
template <typename Variant, typename Handler>
auto with_string_view(Variant const & variant, Handler && handler) {
return std::visit(overloaded{
[&](auto const & obj) {
using std::to_string;
return handler(to_string(obj));
},
[&](std::string const & str) {return handler(str); },
[&](std::string_view str) { return handler(str); },
[&](char const * str) { return handler(str); }
}, variant);
}
Since the temporary created in the generic version outlives the call to the handler, this is safe and efficient. It also shows the "forward it on" technique that I've found to be very useful with variants (and visiting in general, even for non-variants.)
Also, I don't explicitly convert to string_view, but the function could add requirements that the handler accepts string views (if that helps document the usage.)
With the above helper function you might use it like this:
using V = std::variant<std::string, double>;
V v1{4.567};
V v2{"foo"};
auto print = [](std::string_view sv) { std::cout << sv << "\n";};
with_string_view(v1, print);
with_string_view(v2, print);
Here's a full live example, expanded out a little too: https://godbolt.org/z/n7KhEW7vY
If thread safety is not an issue, you could simply use a static std::string as the backing storage when returning a double value. Then you would be able to return a std::string_view, eg:
std::string_view string_from(const Variant& v)
{
static std::string buffer;
return std::visit(overloaded {
[&buffer](const double arg) -> std::string_view { buffer = std::to_string(arg); return buffer; },
[](const std::string& arg) -> std::string_view { return arg; },
}, v);
}
Online Demo
I've come up with my own solution inspired by apple apple's solution with the view_as_string class.
Here it is:
class owning_string_view : public std::string_view
{
public:
explicit owning_string_view(const char* str) : std::string_view{str}, m_string_buffer{} {}
explicit owning_string_view(const std::string& str) : std::string_view{str}, m_string_buffer{} {}
explicit owning_string_view(std::string&& str) : std::string_view{}, m_string_buffer{std::move(str)}
{
static_cast<std::string_view&>(*this) = m_string_buffer;
}
private:
std::string m_string_buffer;
};
Instead of taking a Variant I made it more generic and it takes strings instead.
For lvalue strings it just creates a std::string_view of the string.
For rvalue strings it moves the string into the buffer.
It extends from std::string_view so it can be used in std::string_view contexts seamlessly.
Of course you have to be careful not no slice off the std::string_view part from the object when creating an rvalue owning_string_view but this is true for std::string_view as well. You have to be careful not to take a std::string_view from an rvalue std::string.
Passing a owning_string_view as a std::string_view parameter to a function is safe for the same reason it is safe to pass an rvalue std::string as a std::string_view parameter to a function. The rvalue lives during the function call.
I also realized a deeper problem when returning a string_view from my Variantclass.
If I try to extract a std::string_view or a owning_string_view from an rvalue Variant I'm still going do end up with a dangling string_view, so I added 2 functions for taking a string from the Variant:
one accepts lvalue variants only and it returns owning_string_view.
the other accepts rvalue variants only and it returns a std::string, which is moved from the variant (since the variant is an rvalue).
One more observation: Ideally, I would make the first 2 constructors of owning_string_view constexpr but I can't because the default constructor of std::string is not constexpr. I hope this is changed in the future.
I have a working piece of C++17 code that I would like to port to C++14 (project's constraints). The code allocates a functor on the heap, based on the lambda returned by a provider.
decltype(auto) fun_provider(std::string msg)
{
return [msg](){ std::cout << msg << std::endl; };
}
int main()
{
auto fun = std::make_unique<
std::invoke_result_t<decltype(fun_provider), std::string>
>(fun_provider("Provided functor"));
(*fun.get())()
}
// output: "Provided functor"
The point is, it avoids hardcoding lambda type as std::function<void()>. Up to my best knowledge, the closure type is unspecified and such construction would imply unnecessary copy of the closure object (hope that's correct).
I would like to achieve the same goal with C++14, is it possible? I tried few constructions with std::result_of and/or decltype but didn't succeed so far.
How about routing fun_provider's return value through another pass of template deduction?
template <class T>
auto to_unique(T&& orig) {
using BaseType = std::remove_cv_t<std::remove_reference_t<T>>;
return std::make_unique<BaseType>(std::forward<T>(orig));
}
int main()
{
auto fun = to_unique(fun_provider("Provided functor"));
(*fun.get())();
}
Is this approach not viable?
auto fun = std::make_unique<
decltype(fun_provider(std::declval<std::string>()))
>(fun_provider("Provided functor"));
The use of std::declval isn't even necessary; std::string{} instead of std::declval<std::string>() is just fine.
Just for the sake of completeness and to answer the original question.
The correct solution using std::result_of_t would look like this:
auto fun = std::make_unique<
std::result_of_t<decltype(&fun_provider)(std::string)>
>(fun_provider("Provided functor"));
Background
I have a series of lambdas that perform different checks on the captured variables and return std::nullopt if the check failed. return std::nullopt is the first return statement. Then, if the check succeeded, they go on and compute the value.
Problem
The types of return expressions are not consistent, e.g. std::nullopt_t cannot be converted to std::optional<T>, even though the other way around works. In particular, I'd like the following code to compile and run, printing 2:
#include <functional>
#include <utility>
#include <optional>
int x = 3;
auto lambda = [](){
if (x == 2)
return std::nullopt;
return std::optional(2);
};
#include <iostream>
int main () {
using return_type = std::invoke_result_t<decltype(lambda)>;
static_assert(std::is_same<return_type, std::optional<int>>{},
"return type is still std::nullopt_t");
std::cout << lambda().value() << '\n';
}
Wandbox Demo.
Thoughts
I believe that I need to use std::common_type<Args...> somewhere, but I can neither enforce presence of it or deduce Args, as it might require language support.
Instead of using template type deduction to infer the return type of the lambda, why not explicitly specify that return type?
auto lambda = []() -> std::optional<int> {
if (x == 2)
return std::nullopt;
return 2;
};
std::common_type is commonly with templates, which you don't have.
I suggest to stick with a single return statement and explicitly specified result type without using nullopt at all. It looks somewhat misleading when a function returns either an integer or a nullopt. Especially if the function was longer. Also if value type was something with an explicit constructor then use of emplace allows to avoid typing value type name again.
auto lambda = []()
{
std::optional<int> result{};
if(2 != x)
{
result.emplace(2);
}
return result;
};
Let assume that we have a function that returns a complex object like std::string:
std::string find_path(const std::string& filename);
Is it worthwhile to store the result of calling that method in the const auto&?
void do_sth() {
//...
const auto& path = find_path(filename);
//...
}
That kind of approach prevents copying/moving the object. So it is good. But on the other hand, auto has been introduced to unify the left side of assignation. Herb Sutter in his presentation from CppCon2014 mentions about C++ left-to-right modern style https://www.youtube.com/watch?v=xnqTKD8uD64 (39:00-45:00).
In C++98 storing the std::string at const ref was fine. How is it in C++11?
Update (2016-07-27 2:10 GMT+0):
Sorry, my question was not precise. I meant the coding style - is it better to add const & or just stay with auto only and let the compiler do whatever it want.
Updated example:
unsigned int getTimout() { /* ... */ }
int getDepth() { /* ... */ }
std::string find_path(const std::string& filename,
unsigned int timeout,
int depth) { /* ... */ }
void open(const std::string& path) { /* ... */ }
Two approaches:
void do_sth() {
//...
auto timeout = getTimeout();
auto depth = getDepth();
const auto& path = find_path(filename, timeout, depth);
open(path)
//...
}
vs
void do_sth() {
//...
auto timeout = getTimeout();
auto depth = getDepth();
auto path = find_path(filename, timeout, depth);
open(path);
//...
}
The question: should we
use const auto& to store complex return objects and auto for primitives, or
use auto for everything to keep the left-to-right modern C++ style that Herb mentioned in his presentation (link above).
In C++98 storing the std::string at const ref was fine. How is it in C++11?
Binding a const reference to a temporary string object is fine in C++11. It still has the same behaviour as before.
The theoretical cost of copy-initialization from a temporary (avoiding of which is the advantage of using a const reference) has been greatly reduced in C++11, since moving a string is far cheaper than copying.
The practical cost of copy-initialization has not changed with optimizing compilers, because they may elide the copy/move anyway, so there is no cost - although, whether that is possible, depends on how find_path is implemented.
If you absolutely want to avoid copying/moving the returned string and cannot assume copy elision, then you must create the object outside the function, and pass it to the function by reference. Binding a reference to the return value is not sufficient.
If you want to avoid copying/moving the returned string and can assume copy elision, then using a regular object is just as good as a const reference.
What are the benefits of using boost::any_range?
Here is an example:
typedef boost::any_range<
int
, boost::forward_traversal_tag
, int
, std::ptrdiff_t
> integer_range;
void display_integers(const integer_range& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
int main(){
std::vector<int> input{ ... };
std::list<int> input2{ ... };
display_integers(input);
display_integers(input2);
}
But the same functionality with more efficiency can be achieved with a template parameter, which satisfies the ForwardRange concept:
template <class ForwardRange>
void display_integers(const ForwardRange& rng)
{
boost::copy(rng,
std::ostream_iterator<int>(std::cout, ","));
std::cout << std::endl;
}
So I am searching for scenarios when it is worth to use any_range. Maybe I am missing something.
This technique is called Type Erasure. There is a full article describing the pros and cons on the example of any_iterator: On the Tension Between Object-Oriented and Generic Programming in C++.
It is possible to hide (in a separate file/library) the implementation/definition of
void display_integers(const integer_range& rng)
But in the case of
template <class ForwardRange>
void display_integers(const ForwardRange& rng)
you have to provide source code to users (or at least make explicit instantiations somewhere).
Moreover, in the first case, display_integers will be compiled only once, but in the second it will be compiled for every type of the passed range.
Also, you may have somewhere
integer_range rng;
and during lifetime of rng you may assign ranges of different types to it:
vector<int> v;
list<int> l;
integer_range rng;
rng = v;
rng = l;
The biggest disadvantage of type erasure is its runtime cost; all operations are virtual, and cannot be inlined (easily).
P.S. another famous example of type erasure is std::function
boost::any_range can used for returning ranges from functions. Imagine the following example:
auto make_range(std::vector<int> v) -> decltype(???)
{
return v | filter([](int x){ return x % 2 == 0;})
| transform([](int x){ return x * 2;});
}
*: gcc does not compile the above without wrapping it in std::function, hower clang 3.2 works by directly passing the lambda
It is very difficult to know what is being returned from this function. Also, lambda and decltype don't work together so we cannot deduce the type using decltype when passing only a lambda. One solution is to use boost::any_range like the one in your example (another workaround is to use std::function as pointed out by Evgeny Panasyuk in the comments):
integer_range make_range(std::vector<int> v)
{
return v | filter([](int x){ return x % 2 == 0;})
| transform([](int x){ return x * 2;});
}
Working example with gcc using std::function.
Working example with clang passing lambdas directly.