- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
根据 http://en.cppreference.com/w/cpp/utility/functional/bind , 对于 std::bind
Member function operator()
...
If some of the arguments that are supplied in the call to g() are not matched by any placeholders stored in g, the unused arguments are evaluated and discarded.
引用例子,可以做到:
void f(int n1, int n2, int n3, const int& n4, int n5) {
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int main() {
auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
n = 10;
f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
}
如果你把 f1
当作一个有 5 个参数的函数,其中 3 个是固定的,那么按常理你应该不能调用有 3 个参数的 f1
。但是,如上面的代码所示,您可以这样做,因为额外的参数会被静默忽略。
根据 Why do objects returned from bind ignore extra arguments? ,这种行为之所以存在,是因为实现起来方便??。
对我来说,这是一个相当令人困惑的库功能,因为它打乱了函数的数量(例如上例中的 5 - 3 = 3)并且打败了关于函数调用的推理。我想知道是否有任何实际用例可以证明这种行为实际上是有益的?
更重要的是,是否可以实现 std::bind
的变体来禁止这种行为?这里的可能性和困难是什么。
谢谢
最佳答案
注意:限制参数的数量会破坏 Binder 的一个特性,如图所示 here .
我的解决方案基于
计算传递的占位符
确定使用的最大占位符。感谢Xeo指出这个错误。
#include <functional>
#include <type_traits>
#include <utility>
template<class T, class U>
constexpr auto c_max(T&& t, U&& u)
-> typename std::remove_reference<decltype( t > u ? t : u )>::type
{ return t > u ? t : u; }
template<class...>
struct max_placeholder : std::integral_constant<int, 0> {};
template<class T, class... Rest>
struct max_placeholder<T, Rest...>
: std::integral_constant<int, c_max(std::is_placeholder<T>::value,
max_placeholder<Rest...>::value)>
{};
这给 Binder 用户带来了正确计算数量的负担。对于某些绑定(bind)的 Callable,例如函数指针,可以推断出参数的数量(这也允许自动提供所需数量的占位符)。一旦您以任何一种方式固定了参数的数量,就很容易编写一个包装器来存储 Binder 并提供一个 operator()
模板来检查参数的数量:
template<class T, int N>
struct strict_binder
{
T binder;
template<class... Args>
auto operator()(Args&&... args)
-> decltype( binder(std::forward<Args>(args)...) )
{
static_assert(sizeof...(args) == N, "wrong number of arguments");
return binder(std::forward<Args>(args)...);
}
};
也有可能产生替换失败而不是错误。
由于 strict_binder
是一个 binder
,您可以通过部分特化来表达这个概念:
namespace std
{
template<class T, int N>
struct is_bind_expression< strict_binder<T, N> >
: public true_type
{};
}
剩下的就是编写一个生成 strict_binder
的函数模板。这是一个类似于 std::bind
的版本:
template<class F, class... Args>
auto strict_bind(F&& f, Args&&... args)
-> strict_binder<
typename std::decay<
decltype( std::bind(std::forward<F>(f), std::forward<Args>(args)...) )
>::type,
max_placeholder<typename std::remove_reference<Args>::type...>::value
>
{
return { std::bind(std::forward<F>(f), std::forward<Args>(args)...) };
}
本质上,返回类型是一个
strict_binder<decltype(std::bind(f, args...)), count_placeholders<Args...>::value>
也就是说,strict_binder
存储了 std::bind
的结果类型。
您还可以编写类似apply
的函数,在未传递占位符时调用绑定(bind)函数:
template<int N, class F, class... Args>
auto strict_bind_or_call(std::integral_constant<int, N>, F&& f, Args&&... args)
-> strict_binder<
typename std::decay<
decltype( std::bind(std::forward<F>(f), std::forward<Args>(args)...) )
>::type,
N
>
{
return { std::bind( std::forward<F>(f), std::forward<Args>(args)... ) };
}
template<class F, class... Args>
auto strict_bind_or_call(std::integral_constant<int, 0>, F&& f, Args&&... args)
-> decltype( std::bind( std::forward<F>(f), std::forward<Args>(args)... ) () )
{
return std::bind( std::forward<F>(f), std::forward<Args>(args)... ) ();
}
template<class F, class... Args>
auto strict_bind(F&& f, Args&&... args)
-> decltype( strict_bind_or_call( std::integral_constant<int, max_placeholder<typename std::remove_reference<Args>::type...>::value>{},
std::forward<F>(f), std::forward<Args>(args)... ) )
{
using max_placeholder_here =
max_placeholder<typename std::remove_reference<Args>::type...>;
return strict_bind_or_call( max_placeholder_here{},
std::forward<F>(f), std::forward<Args>(args)... );
}
这使用标记分派(dispatch)来返回绑定(bind)器或调用函数的结果。我放弃了正确格式化,您可能想在 detail
命名空间中引入别名模板。
请注意 strict_bind_or_call
的第二个重载中的 decltype( std::bind(..) () )
是重现 语义的简单方法调用
/绑定(bind)
;我不能只写 f(args...)
因为 f
可能是一个成员函数。
使用示例:
#include <iostream>
void foo(int p0, int p1)
{ std::cout << "[" << p0 << ", " << p1 << "]\n"; }
int main()
{
auto f0 = strict_bind(foo, std::placeholders::_1, 42);
f0(1);
strict_bind(foo, 1, 2);
}
关于c++:如何编写一个类似 std::bind 的对象来检查多余的参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21762844/
我的服务层有如下方法 public ModuleResponse GetModules(ModuleRequest request) { var response = new ModuleRe
我构建的工具栏与大多数工具栏一样,minHeight 设置为 actionBarSize: 但是,如果我删除这个属性,就完全没有区别了。工具栏保持其 actionBarSize,即使我删除菜单并将
我已经为 SVG 和剪辑路径苦苦挣扎了一段时间。 我正在尝试创建一个三 Angular 形剪辑路径,它将覆盖照片以给顶部一个“三 Angular 形”边缘。 我试图实现与照片完全相同的效果,但三 An
我有一个带有 2 个索引的 PostgreSQL 表。其中一个索引涵盖了 website_id 和 tweet_id 列,是一个唯一的 B 树索引。第二个索引只覆盖 website_id 列,是一个非
我是一名优秀的程序员,十分优秀!