I want to know how to declare an object of the return type of std::function
when used with pointer to a member function:
int main(){
void foo(std::string, int);
string s = "hi";
auto fn = std::bind(foo, s, std::placeholders::_1);
fn(5);// ok
/*auto fn2 = */std::bind(&std::string::empty, std::placeholders::_1); // error if I uncomment /*auto fn2 = */
std::vector<std::string> vs{"The", "Quick", "Brown", "Fox", "Jumped", "", "Over", "The", "", "Lazy", "Dog"};
auto it = std::find_if(vs.cbegin(), vs.cend(),
std::bind(&std::string::empty, std::placeholders::_1)); // OK
std::cout << "Empty string found at index: " << (it != vs.cend() ? std::distance(vs.cbegin(), it) : -1) << '\n'; // 5
std::cout << "\ndone!\n";
}
- If I un-comment
auto fn2 =
I get an error:
||=== Build: Debug in myproj (compiler: GNU GCC Compiler) ===| /home/Itachi57/Desktop/myproj/main.cxx||In function ‘int main()’:| /home/Itachi57/Desktop/myproj/main.cxx|845| in ‘constexpr’ expansion of ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = bool (std::__cxx11::basic_string<char>::*)() const noexcept; _BoundArgs = {const std::_Placeholder<1>&}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind_helper<false, bool (std::__cxx11::basic_string<char>::*)() const noexcept, const std::_Placeholder<1>&>::type](std::placeholders::_1)’| /home/Itachi57/Desktop/myproj/main.cxx|845|internal compiler error: Segmentation fault| ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 7 second(s)) ===|
So Why if I call
bind
without storing its returned value usingauto
when binding a pointer to a member function is OK but I can't store that value (new callable)?In fact this is just for practice purpose because in real I'd prefer to use
std::mem_fn
andstd::function
.Update:
If I run the program from a terminal:
g main.cxx -std=c 2a -o prog && ./prog
It works just fine.
I've found out that one day I've disabled "Copy-elision optimization" from CodeBlocks:
-fno-elide-constructors
Now If I remove this and let the CodeBlocks apply it (Copy-elision opt.) the program build and works just fine!
- So does this error have a relationship with Copy-Elision Optimization? Thank you!
CodePudding user response:
// error if I uncomment /*auto fn2 = */
// OK
Actually, no, it's not okay. The C standard doesn't generally permit taking the address of functions defined in namespace std (be they free or members). The exceptions are always marked explicitly as addressable functions, and std::string::empty
is not addressable.
Why? Implementation leeway and future proofing. The standard may want to add overloads. The implementation may want to use overloads to implement the standard-mandated behavior, or even templates. For that to be possible, and our program be well-defined by the standard, we cannot do &std::string::empty
.
Just use lambdas to wrap standard functions that aren't addressable (as you would anyway with your own overload sets). Actually... just use lambdas and forget about std::bind
, they are better in practically every way.
CodePudding user response:
It's perfectly fine implementation defined:
#include <functional>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
void foo(std::string, int) {}
int main()
{
auto fn = std::bind(&std::string::empty, std::placeholders::_1);
std::vector<std::string> vs{"The", "Quick", "Brown", "Fox", "Jumped", "",
"Over", "The", "", "Lazy", "Dog"};
auto it = std::find_if(vs.cbegin(), vs.cend(), fn);
std::cout << "Empty string found at index: "
<< (it != vs.cend() ? std::distance(vs.cbegin(), it) : -1)
<< '\n'; // 5
std::cout << "\ndone!\n";
}
Prints
Empty string found at index: 5
done!
Simplify
I'd use std::mem_fn
:
std::vector<std::string> vs{
"The", "Quick", "Brown", "Fox", "Jumped", "",
"Over", "The", "", "Lazy", "Dog",
};
auto it = std::find_if(vs.cbegin(), vs.cend(), std::mem_fn(&std::string::empty));
std::cout << "Empty string found at index: " << (it - vs.begin()) << '\n';
Not using Bind of legacy function types:
Consider using a C 11 lambda: Coliru
auto it = std::find_if(vs.cbegin(), vs.cend(),
[](std::string const& s) { return s.empty(); });