简体   繁体   中英

Why does std::bind accept more arguments than possible for bound function?

I was interested in learning more about the behaviour of std::bind() with member functions, and thought it was odd for MSVC to compile the following code when no other compiler I tried would. Is MSVC wrong to compile this?

I tried GCC, CLang, and some other minor compilers in the compiler explorer side-by-side with MSVC: https://godbolt.org/z/DNtP-o

Only MSVC would compile this:

#include <functional>

struct S{
    void f(int){}
};

int main(){
    S s;
    auto binding = std::bind(&S::f,s, 5,3);

    return 0;
}

These are the errors I get from compiling with 'x86-64 clang 8.0.0':

error: static_assert failed due to requirement 'integral_constant<bool, false>::value ? sizeof...(_BoundArgs) >= integral_constant<unsigned long, 1>::value + 1 : sizeof...(_BoundArgs) == integral_constant<unsigned long, 1>::value + 1' "Wrong number of arguments for pointer-to-member"

error: no matching function for call to 'bind'

None of the compilers are wrong here, since the program has undefined behavior.

Note that MSVC does of course give errors if you actually try to call the bound functor. So the question is fairly academic, since in a real program using std::bind to create something that can never be called on any code path is not very useful.

C++17 [func.bind.bind]/2 says:

Requires: ... INVOKE (fd, w_1, w_2, ..., w_N) shall be a valid expression for some values w_1 , w_2 , ... w_N , where N has the value sizeof...(bound_args) . ...

But this is a requirement on code using the standard library, not on implementations (compilers and/or libraries), and nothing says implementations must diagnose a violation. Violating a Requires: paragraph is undefined behavior unless otherwise noted.

So the ability of g++ and clang++ (when using libstdc++) to notice the problem at the std::bind call is just a nice quality of implementation bonus feature.

Presumably libstdc++ does this by template matching on a pointer to (member) function. But in the more general case, determining whether there might be any way to call a functor with a given number of arguments of wildcard types is more difficult or impossible. All three compilers accept this code with no errors or warnings:

#include <functional>

struct X {
    void operator()() const;
    void operator()(int) const;
};

void f() {
    auto func = std::bind(X{}, 2, 3, 4);
    static_cast<void>(func);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM