3

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 using auto 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 and std::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!
Itachi Uchiwa
  • 3,044
  • 12
  • 26

2 Answers2

5

// 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.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    Woah. How come I hear about this for the first time today. Is there a canonical reference (outside the standardese?) – sehe Nov 02 '21 at 22:42
  • 2
    @sehe - https://en.cppreference.com/w/cpp/language/extending_std#Other_restrictions has a summary. But it's almost word for word the standardese. – StoryTeller - Unslander Monica Nov 02 '21 at 22:43
  • Good enough. I was only specifying to avoid the rabbit hole of a hundred scattered wordings that effectively mean something :) As long as it's in one place, that's a good reference to use in the future. – sehe Nov 02 '21 at 22:44
  • Oups ... I need to revise all my answers here where I've taken the address of misc `std::` functions... Jeez ... I've used that mainly for the `cctype` functions but I couldn't find anything about even those being ok... – Ted Lyngmo Nov 02 '21 at 22:47
  • In fact I prefer use `std::function` and `std::mem_fn` instead but this is just for practice purpose. I've updated the topic. Please take a look. – Itachi Uchiwa Nov 02 '21 at 22:50
  • @TedLyngmo - I'm not sure how it reflects on the `c*` headers. It's a library wide requirement, but then again... C... I vaguely recall the C standard allowing an implementation to make some functions into macros. That would break too I suppose. – StoryTeller - Unslander Monica Nov 02 '21 at 22:52
  • @ItachiUchiwa - You aren't using `std::function`. It's completely orthogonal to `std::bind`. – StoryTeller - Unslander Monica Nov 02 '21 at 22:52
  • @StoryTeller-UnslanderMonica Thanks. I'm hoping that I've been lucky then but will try to remember to play it safe the next time. – Ted Lyngmo Nov 02 '21 at 22:54
  • I'd say it is less restrictive than "non permitting". "The behavior of a C++ program is unspecified (possibly ill-formed) " it **might** be OK to take the address, or it might not be OK depending on implementation. – SergeyA Nov 02 '21 at 22:55
  • @SergeyA - Are we here to split hairs or to write programs that will do what we except and compile successfully in portable fashion? You wanna argue it's "less bad" because explicit nasal demons are off the table? Fine, knock yourself out. It's still not permitted, and to do so is to build on quicksand. – StoryTeller - Unslander Monica Nov 02 '21 at 23:00
  • I am not interested in splitting hairs. It is not "not permitted" by standard, it is rather that implementations is not required to support it. Those are different positions, as with implementation defined vs undefined. One can research their implementation and write code which is conformant with it. – SergeyA Nov 03 '21 at 19:27
  • @SergeyA - I guess it's a NLP sort of problem. When the standard says "this is addressable" it *permits* one to take its address, rather explicitly I might add. When it doesn't... it doesn't. And if you aren't interested in splitting hairs, don't follow that claim by doing just that. – StoryTeller - Unslander Monica Nov 03 '21 at 20:10
2

It's perfectly fine implementation defined:

Live On Coliru

#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:

Live On Coliru

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(); });
sehe
  • 374,641
  • 47
  • 450
  • 633