如何实现自动插入隐含占位符的 easy_bind()? *带成员指针*
How to implement an easy_bind() that automagically inserts implied placeholders? *With member pointers*
我想到了这个有趣的解决方案 (here with an example here) 来创建 std::bind 类型的函数,而无需显式放置占位符。
任务
实现类似的绑定函数,但不能将值放入绑定调用中(我不需要它。)并添加调用此新绑定函数以绑定成员指针的能力。
我设法做了什么
所以我想出了如何使用虚拟 std::function 来获取函数的签名。
我还想出了如何删除向 bins 调用添加值的功能。
这是我的代码:
#include <functional>
#include <type_traits>
#include <utility>
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class Fn, class... Args>
auto my_bind(indices<Is...>, Fn const &f, Fn *i, Args&&... args)
-> decltype(std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
return std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
}
}
template<class Ret, class... FArgs, class Fn, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args)
-> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){
return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...);
}
#include <iostream>
struct tmp{
void testt(int var1, int var2){
std::cout << var1 << " " << var2 << std::endl;
}
};
int main(){
tmp TMP;
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
f3(22, 23);
}
问题
我试图将成员指针传递给模板,但是我遇到了编译器错误。 (问题似乎与成员指针的传递有关)我尝试了其他传递成员指针的方法,例如 here and here 所描述的,但是使用这些方法我没有取得任何进展。
错误如下:
g++ -std=c++11 -Wall -W -pedantic -O2 hello-cpp-world.cc -o hello-cpp-world
hello-cpp-world.cc: In function ‘int main()’:
hello-cpp-world.cc:68:73: error: no matching function for call to ‘my_bind(std::function<void(int, int)>, void (tmp::*)(int, int), tmp*)’
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
^
hello-cpp-world.cc:68:73: note: candidate is:
hello-cpp-world.cc:48:6: note: template<class Ret, class ... FArgs, class Fn, class ... Args> decltype (detail::my_bind(build_indices<(sizeof (FArgs ...) - sizeof (Args ...))>{}, f, (& i), (forward<Args>)(my_bind::args)...)) my_bind(std::function<_Res(_ArgTypes ...)>, const Fn&, Fn*, Args&& ...)
auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args) -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){
^
hello-cpp-world.cc:48:6: note: template argument deduction/substitution failed:
hello-cpp-world.cc:68:73: note: deduced conflicting types for parameter ‘Fn’ (‘void (tmp::*)(int, int)’ and ‘tmp’)
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
^
make: *** [hello-cpp-world] Error 1
问题
- 我想要达到的目标是否可行? (虽然我很确定是)
- 如果是这样,如何解决?
您的代码有两个关键问题:
- 你一直在获取你想要调用成员函数的对象的地址。一旦实体是一个指针,获取它的地址对你没有多大好处。
- 一个成员函数指针和它的第一个参数显然有不同的类型。要么您需要提供它的正确签名,要么从成员函数指针类型中提取第一个参数类型,要么让相应的参数类型不受约束并让类型系统排除无效使用。后一种方法还有一个优点是可以传递引用和智能指针。
这是您的代码的补丁版本,可以编译:
#include <functional>
#include <type_traits>
#include <utility>
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class Ret, class Fn, class... MArgs, class... Args>
auto my_bind(indices<Is...>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args)
-> decltype(std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
return std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
}
}
template<class Ret, class... FArgs, class Fn, class... MArgs, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args)
-> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...)){
return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...);
}
#include <iostream>
struct tmp{
void testt(int var1, int var2){
std::cout << var1 << " " << var2 << std::endl;
}
};
int main(){
tmp TMP;
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
f3(22, 23);
}
我想到了这个有趣的解决方案 (here with an example here) 来创建 std::bind 类型的函数,而无需显式放置占位符。
任务
实现类似的绑定函数,但不能将值放入绑定调用中(我不需要它。)并添加调用此新绑定函数以绑定成员指针的能力。
我设法做了什么
所以我想出了如何使用虚拟 std::function 来获取函数的签名。
我还想出了如何删除向 bins 调用添加值的功能。
这是我的代码:
#include <functional>
#include <type_traits>
#include <utility>
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class Fn, class... Args>
auto my_bind(indices<Is...>, Fn const &f, Fn *i, Args&&... args)
-> decltype(std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
return std::bind(f, &i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
}
}
template<class Ret, class... FArgs, class Fn, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args)
-> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){
return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...);
}
#include <iostream>
struct tmp{
void testt(int var1, int var2){
std::cout << var1 << " " << var2 << std::endl;
}
};
int main(){
tmp TMP;
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
f3(22, 23);
}
问题
我试图将成员指针传递给模板,但是我遇到了编译器错误。 (问题似乎与成员指针的传递有关)我尝试了其他传递成员指针的方法,例如 here and here 所描述的,但是使用这些方法我没有取得任何进展。
错误如下:
g++ -std=c++11 -Wall -W -pedantic -O2 hello-cpp-world.cc -o hello-cpp-world
hello-cpp-world.cc: In function ‘int main()’:
hello-cpp-world.cc:68:73: error: no matching function for call to ‘my_bind(std::function<void(int, int)>, void (tmp::*)(int, int), tmp*)’
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
^
hello-cpp-world.cc:68:73: note: candidate is:
hello-cpp-world.cc:48:6: note: template<class Ret, class ... FArgs, class Fn, class ... Args> decltype (detail::my_bind(build_indices<(sizeof (FArgs ...) - sizeof (Args ...))>{}, f, (& i), (forward<Args>)(my_bind::args)...)) my_bind(std::function<_Res(_ArgTypes ...)>, const Fn&, Fn*, Args&& ...)
auto my_bind(std::function<Ret(FArgs...)>, Fn const&f, Fn *i, Args&&... args) -> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, &i, std::forward<Args>(args)...)){
^
hello-cpp-world.cc:48:6: note: template argument deduction/substitution failed:
hello-cpp-world.cc:68:73: note: deduced conflicting types for parameter ‘Fn’ (‘void (tmp::*)(int, int)’ and ‘tmp’)
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
^
make: *** [hello-cpp-world] Error 1
问题
- 我想要达到的目标是否可行? (虽然我很确定是)
- 如果是这样,如何解决?
您的代码有两个关键问题:
- 你一直在获取你想要调用成员函数的对象的地址。一旦实体是一个指针,获取它的地址对你没有多大好处。
- 一个成员函数指针和它的第一个参数显然有不同的类型。要么您需要提供它的正确签名,要么从成员函数指针类型中提取第一个参数类型,要么让相应的参数类型不受约束并让类型系统排除无效使用。后一种方法还有一个优点是可以传递引用和智能指针。
这是您的代码的补丁版本,可以编译:
#include <functional>
#include <type_traits>
#include <utility>
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<int I> struct placeholder{};
namespace std{
template<int I>
struct is_placeholder< ::placeholder<I>> : std::integral_constant<int, I>{};
} // std::
namespace detail{
template<std::size_t... Is, class Ret, class Fn, class... MArgs, class... Args>
auto my_bind(indices<Is...>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args)
-> decltype(std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...)){
return std::bind(f, i, std::forward<Args>(args)..., placeholder<1 + Is>{}...);
}
}
template<class Ret, class... FArgs, class Fn, class... MArgs, class... Args>
auto my_bind(std::function<Ret(FArgs...)>, Ret (Fn::*f)(MArgs...), Fn *i, Args&&... args)
-> decltype(detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...)){
return detail::my_bind(build_indices<sizeof...(FArgs) - sizeof...(Args)>{}, f, i, std::forward<Args>(args)...);
}
#include <iostream>
struct tmp{
void testt(int var1, int var2){
std::cout << var1 << " " << var2 << std::endl;
}
};
int main(){
tmp TMP;
auto f3 = my_bind(std::function<void(int, int)>(), &tmp::testt, &TMP);
f3(22, 23);
}