被 std::bind 分离的 std::function 的模板类型是未定义的行为吗?

问题描述

我正在研究 MSVC

static bool filter_entity(void* entity)
{
    return entity == nullptr;
};
template<typename F>
static bool dispatch(const F& filter)
{
    return filter(nullptr);
};
int main()
{
    void* ptr = new int();
    if (dispatch(std::bind(&filter_entity,ptr))) cout << "nullptr" << endl;
    else cout << "intptr" << endl;
    //ret: intptr
}

奇怪的是,使用 const nullptr 参数调用函数实际上将 ptr 作为参数插入,我想知道这是否是未定义的行为。

还有没有办法为此实例调用 filter() 并使模板和 std::bind 在多种情况下都有意义?

解决方法

来自cppreference.com

如果在对 [绑定对象] 的调用中提供的某些参数与存储在 [绑定对象] 中的任何占位符都不匹配,则未使用的参数将被评估并丢弃。

问题中的绑定对象没有占位符。所以

中的nullptr
return filter(nullptr);

求值并丢弃,结果与if相同

return filter();

被调用。如果我们解释绑定,这与

相同
return filter_entity(ptr);

(或者如果 ptr 在范围内)。如果要在 return 语句中使用 nullptr,则需要在 std::placeholders::_1 中使用 std::bind


对此的后续问题可能是Why do objects returned from bind ignore extra arguments?

,

停止使用 std::bindstd::bind 不值得成为专家。而是成为 lambdas 的专家。

std::bind 中的 boost::bind 导入,同时 lambdas 到达。这是一个库解决方案,lambdas 解决了许多与它相同的问题。在 中,std::bind 可以做一些 lambdas 不能做的事情;从那以后 lambda 变得更加诗意,这不再是真的。

std::bind 充满了奇怪的角落。你正在见证其中之一;老实说,其中一个比较行人。


std::bind 不返回 std::functionstd::bind 返回带有 operator() 的未命名对象。当您对其调用 operator() 时,它首先获取其绑定参数(或者是对引用进行一些解包),根据占位符和绑定子表达式进行一些重新路由。

在那里完成一个复杂的步骤后,它会“悄悄地”丢弃额外的参数。

所以你将第一个参数绑定到 nullptr;后面的非空值被评估并丢弃。