使自由函数的行为像成员函数 (C++)
Make a free function behave like a member function (C++)
假设我在 C++ 中有如下函数:
template<typename Container>
void doNothing(Container * container) {
for (auto element: container) {
std::cout << element;
}
}
是否可以通过向其传递 this
而不是第一个参数来实现此功能的各种 class 上的 "simulate" 方法。 (例如 class 如 std::vector、std::string ... 等)。
所以基本上不必将其用作:
std::vector<double> a{1, 2, 0.5}:
doNothing(a);
我可以这样称呼它:
std::vector<double> a{1, 2, 0.5}:
a.doNothing();
您始终可以通过传递对象的 this
指针来模拟成员函数。
毕竟,这就是编译器为适当的成员函数所做的全部工作(将 this
作为隐藏的第一个参数传递)。
因此,如果您希望函数 foo
表现得像一个成员并在类型 Bar
的对象(此处忽略 private/protected)上操作,那么您可以将其声明为:
void foo(Bar* self);
并称其为
Bar b;
foo(&b);
(或来自 Bar
成员:foo(this);
)
然后它将能够访问 b
的成员并通过取消引用 self
指针来调用它的函数。
不,你不能那样做。
调用 a.b()
中的 this
参数是隐式的,无法伪造隐式参数。
除非 b
是成员,否则 a.b()
语法根本不可用。
template<class F>
struct poly_mem_ptr_t{
F f;
template<class T>
friend auto operator->*( T* t, poly_mem_ptr_t self )const{
return
[t, f=self.f](auto&&...args)->decltype(auto){
return f(t, decltype(args)(args)...);
};
}
template<class T>
friend auto operator->*( T& t, poly_mem_ptr_t self )const{
return std::addressof(t)->*self;
}
};
template<class F>
poly_mem_ptr_t<F> poly_mem_ptr(F f){ return {std::move(f)}; }
示例使用:
auto do_nothing = poly_mem_ptr([](auto* ptr){ doNothing(ptr); });
std::vector<int> v={1,2,3};
(v->*do_nothing)();
不完全是你想要的,但接近。
作为福利,您可以添加
template<class...Ts>
friend decltype(auto) operator->*( std::variant<Ts...>& var, poly_mem_ptr_t self )const{
return [&var, f=self.f](auto&&...args) {
return std::visit( [&](auto&&t)->decltype(auto){
return f( decltype(t)(t), decltype(args)(args)... );
}, var);
};
}
现在您可以 std::variant
并使用这些 poly_mem_ptr
作为访客。
通过一些工作,您还可以构建一个增强的 std::any
来支持一组固定的 poly_mem_ptr
。
假设我在 C++ 中有如下函数:
template<typename Container>
void doNothing(Container * container) {
for (auto element: container) {
std::cout << element;
}
}
是否可以通过向其传递 this
而不是第一个参数来实现此功能的各种 class 上的 "simulate" 方法。 (例如 class 如 std::vector、std::string ... 等)。
所以基本上不必将其用作:
std::vector<double> a{1, 2, 0.5}:
doNothing(a);
我可以这样称呼它:
std::vector<double> a{1, 2, 0.5}:
a.doNothing();
您始终可以通过传递对象的 this
指针来模拟成员函数。
毕竟,这就是编译器为适当的成员函数所做的全部工作(将 this
作为隐藏的第一个参数传递)。
因此,如果您希望函数 foo
表现得像一个成员并在类型 Bar
的对象(此处忽略 private/protected)上操作,那么您可以将其声明为:
void foo(Bar* self);
并称其为
Bar b;
foo(&b);
(或来自 Bar
成员:foo(this);
)
然后它将能够访问 b
的成员并通过取消引用 self
指针来调用它的函数。
不,你不能那样做。
调用 a.b()
中的 this
参数是隐式的,无法伪造隐式参数。
除非 b
是成员,否则 a.b()
语法根本不可用。
template<class F>
struct poly_mem_ptr_t{
F f;
template<class T>
friend auto operator->*( T* t, poly_mem_ptr_t self )const{
return
[t, f=self.f](auto&&...args)->decltype(auto){
return f(t, decltype(args)(args)...);
};
}
template<class T>
friend auto operator->*( T& t, poly_mem_ptr_t self )const{
return std::addressof(t)->*self;
}
};
template<class F>
poly_mem_ptr_t<F> poly_mem_ptr(F f){ return {std::move(f)}; }
示例使用:
auto do_nothing = poly_mem_ptr([](auto* ptr){ doNothing(ptr); });
std::vector<int> v={1,2,3};
(v->*do_nothing)();
不完全是你想要的,但接近。
作为福利,您可以添加
template<class...Ts>
friend decltype(auto) operator->*( std::variant<Ts...>& var, poly_mem_ptr_t self )const{
return [&var, f=self.f](auto&&...args) {
return std::visit( [&](auto&&t)->decltype(auto){
return f( decltype(t)(t), decltype(args)(args)... );
}, var);
};
}
现在您可以 std::variant
并使用这些 poly_mem_ptr
作为访客。
通过一些工作,您还可以构建一个增强的 std::any
来支持一组固定的 poly_mem_ptr
。