Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mem_fun + bind2nd allows to call a method with an argument of an arbitrary type

Tags:

c++

bind

consider this example (https://ideone.com/RpFRTZ)

This will effectively call Foo::comp (const Foo& a) with a parameter of an unrelated type Bar. Not only does this compile, if I comment out std::cout << "a = " << a.s << std::endl; it also somehow works and prints Result: 0

If I do print out the value, than it segfaults, which is fair enough... But why does it compile in the first place?

#include <functional>
#include <string>
#include <iostream>

struct Foo
{
    bool comp(const Foo& a)
    {
        std::cout << "a = " << a.s << std::endl;
        return a.s == s;
    }

    std::string s;

};

struct Bar
{
    int a;
};


template <class F, class T>
void execute (F f, T a)
{
    std::cout << "Result: " << f (a) << std::endl;

}

int main()
{
    Foo* f1 = new Foo;
    f1->s = "Hello";

    Foo f2;
    f2.s = "Bla";

    Bar b;
    b.a = 100;

    execute (std::bind2nd (std::mem_fun(&Foo::comp), b), f1);


    return 0;
}
like image 968
cppalex Avatar asked Sep 08 '17 10:09

cppalex


1 Answers

The answer is in the implementation of std::bind2nd:

  template<typename _Operation, typename _Tp>
    inline binder2nd<_Operation>
    bind2nd(const _Operation& __fn, const _Tp& __x)
    {
      typedef typename _Operation::second_argument_type _Arg2_type;
      return binder2nd<_Operation>(__fn, _Arg2_type(__x));
    }

You can see that there is an unsafe C-style cast "_Arg2_type(__x)" to the right type, so your example compiles as if it was written:

execute (std::bind2nd (std::mem_fun(&Foo::comp), (const Foo&)b), f1);

which is unfortunately valid C++ code.

like image 191
cyril Avatar answered Sep 22 '22 15:09

cyril