Is it possible to capture by const reference in a lambda expression?
I want the assignment marked below to fail, for example:
#include <algorithm>
#include <string>
using namespace std;
int main()
{
string strings[] =
{
"hello",
"world"
};
static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
string best_string = "foo";
for_each( &strings[0], &strings[num_strings], [&best_string](const string& s)
{
best_string = s; // this should fail
}
);
return 0;
}
Update: As this is an old question, it might be good to update it if there are facilities in C++14 to help with this. Do the extensions in C++14 allow us to capture a non-const object by const reference? (August 2015)
In c++14 using static_cast / const_cast:
[&best_string = static_cast<const std::string&>(best_string)](const string& s)
{
best_string = s; // fails
};
DEMO
In c++17 using std::as_const:
[&best_string = std::as_const(best_string)](const string& s)
{
best_string = s; // fails
};
DEMO 2
const isn't in the grammar for captures as of n3092:
capture:
identifier
& identifier
this
The text only mention capture-by-copy and capture-by-reference and doesn't mention any sort of const-ness.
Feels like an oversight to me, but I haven't followed the standardization process very closely.
I think the capture part should not specify const, as the capture means, it only need a way to access the outer scope variable.
The specifier is better specified in the outer scope.
const string better_string = "XXX";
[&better_string](string s) {
better_string = s; // error: read-only area.
}
lambda function is const(can't change value in its scope), so when you capture variable by value, the variable can not be changed, but the reference is not in the lambda scope.
There is a shorter way.
Note that there is no ampersand before "best_string".
It will be of a const std::reference_wrapper<T> type.
[best_string = std::cref(best_string)](const string& s)
{
best_string = s; // fails
};
http://coliru.stacked-crooked.com/a/0e54d6f9441e6867
I guess if you're not using the variable as a parameter of the functor, then you should use the access level of the current function. If you think you shouldn't, then separate your lambda from this function, it's not part of it.
Anyway, you can easily achieve the same thing that you want by using another const reference instead :
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string strings[] =
{
"hello",
"world"
};
static const size_t num_strings = sizeof(strings)/sizeof(strings[0]);
string best_string = "foo";
const string& string_processed = best_string;
for_each( &strings[0], &strings[num_strings], [&string_processed] (const string& s) -> void
{
string_processed = s; // this should fail
}
);
return 0;
}
But that's the same as assuming that your lambda have to be isolated from the current function, making it a non-lambda.
I think you have three different options:
don't use const reference, but use a copy capture
ignore the fact that it is modifiable
use std::bind to bind one argument of a binary function which has a const reference.
using a copy
The interesting part about lambdas with copy captures is that those are actually read only and therefore do exactly what you want them to.
int main() {
int a = 5;
[a](){ a = 7; }(); // Compiler error!
}
using std::bind
std::bind reduces the arity of a function. Note however that this might/will lead to an indirect function call via a function pointer.
int main() {
int a = 5;
std::function<int ()> f2 = std::bind( [](const int &a){return a;}, a);
}
Use clang or wait until this gcc bug is fixed:
bug 70385: Lambda capture by reference of const reference fails [https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70385]
Using a const will simply have the algorithm ampersand set the string to it's original value,
In other words, the lambda won't really define itself as parameter of the function, though the surrounding scope will have an extra variable...
Without defining it though, it wouldn't define the string as the typical
[&, &best_string](string const s)
Therefore, its most likely better if we just leave it at that, trying to capture the reference.
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 quick question regarding C++ and references to values. I have been asked to write a function that takes the input from const std::string& and use the input to perform some tasks. The issue is, I have no idea how to access the value. I know it is a pass-by reference value but I don't know how to access it within the function.
This is the code that I was given:
#include "rle.hpp"
std::string func_send(const std::string&)
{
//Implement !
return {};
}
std::string func_receive(const std::string&)
{
// Implement!
return {};
}
The code you were given makes no sense, at least there is no way to acces the parameter because it has no name. Moreover std::string str = std::string&; is invalid syntax, I don't know what it is supposed to mean. Give the parameter a name:
std::string func_send(const std::string& str)
// ^------------ !!!
{
std::string some_other_string = str;
return {}; // missing semi-colon
}
I want to use either push_front or push_back depending on user input. Is it possible to have that included in the function parameter, then write one function in order to save on memory?
Is it possible to have that included in the function parameter?
No. You can't.
A good explanation can be found in this discussion:
Can I take the address of a function defined in standard library?
However, a workaround can be done by telling the function explicitly where the insertion should take place.
#include <iostream>
#include <deque>
enum class To{ front = 0, back };
void func(std::deque<int>& dq, const int value, const To where)
{
if (where == To::front)
{
dq.push_front(value);
// code
}
else if(where == To::back)
{
dq.push_back(value);
// code
}
}
And you call it
std::deque<int> dq;
func(dq, 1, To::back);
func(dq, 2, To::front);
It is possible using lambdas:
#include <deque>
void f(bool user_input) {
using C = std::deque<int>;
using FnType = void(*)(C&, int);
FnType const fns[2] = {
[](C& c, int value) { c.push_front(value); },
[](C& c, int value) { c.push_back(value); }
};
C q;
fns[user_input](q, 1);
fns[!user_input](q, 2);
}
In this examples, the closures created by lambda expressions have 0 captures and hence can be converted to plain function pointers. When there are more than 0 captures std::function can be used instead of plain function pointers.
Digging through MSDN, I ran into just another curious line:
// This function returns the constant string "fourth".
const string fourth() { return string("fourth"); }
The full example is buried here: https://msdn.microsoft.com/en-us/library/dd293668.aspx Refined to bare minimum, it looks like this:
#include <iostream>
const int f() { return 0; }
int main() {
std::cout << f() << std::endl;
return 0;
}
A few other tests with different return types demonstrated that both Visual Studio and g++ compile lines like this without a warning, yet const qualifier seems to have no effect on what I can do with the result. Can anyone provide an example of where it matters?
you can not modify the returned object
example:
#include <string>
using namespace std;
const string foo(){return "123";}
string bar(){return "123";}
int main(){
//foo().append("123"); //fail
bar().append("123"); //fine
}
This is almost the same as const variable
#include <string>
using namespace std;
const string foo = "123";
string bar = "123";
int main(){
//foo.append("123"); //fail
bar.append("123"); //fine
}
It is part of the return type. The functions return const string and const int.
In the case of const int, this indeed makes no difference compared to int, because the only thing you can do with an int return value is to copy the value somewhere (in fact, the standard explicitly says that const has no effect here).
In the case of const string, it does make a difference, because a return value of class type can have member functions called on it:
fourth().erase(1);
will fail to compile in the case that fourth() returns a const string, because erase() is not a const method (it tries to modify the string it is called on).
Personally, I never make value-returning functions return a const value, as it unnecessarily constrains the caller (although some people feel that it is useful to prevent writing things like string s = fourth().erase(1);).
I want to submit a handle but I only want it to be executed if a shared pointer is still valid:
// elsewhere in the class:
std::shared_ptr<int> node;
// later on:
const std::weak_ptr<int> slave(node); // can I do this in the capture clause somehow?
const auto hook = [=]()
{
if (!slave.expired())
//do something
else
// do nothing; the class has been destroyed!
};
someService.Submit(hook); // this will be called later, and we don't know whether the class will still be alive
Can I declare slave within the capture clause of the lambda? Something like const auto hook = [std::weak_ptr<int> slave = node,=]().... but unfortunately this doesn't work. I would like to avoid declaring the variable and then copying it (not for performance reasons; I just think it would be clearer and neater if I could create whatever the lambda needs without polluting the enclosing scope).
You can do this using generalized lambda captures in C++14:
const auto hook = [=, slave = std::weak_ptr<int>(node)]()
{
...
};
Here's a live example. Note that since there are no parameters or explicit return type, the empty parameter list (()) can be left out.
As mentioned by chris this is possible in C++14.
If you are willing to modify the captured value simply add mutablespecifier.
Here is an example which fills a vector from zero to the length of the vector.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> container(10);
std::generate(container.begin(), container.end(), [n = 0]() mutable { return n++; });
for (const auto & number : container)
{
std::cout << number << " ";
}
std::cin.ignore();
return 0;
}