这里我有以下类型的仿函数:
template<class T, class Foo, T Foo::*p>
struct X {
void operator()(Foo & f) {
(f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()`
}
};
示例struct:
struct FF
{
int m;
int r;
};
我想使用仿函数X,但我不想如下显式指定模板参数:
void testforx()
{
std::vector<FF> cont(5);
std::for_each(cont.begin(), cont.end(), X<int, FF, &FF::r>() ); // it work, but I don't want to write `int` and `FF`
std::for_each(cont.begin(), cont.end(), createx<&FF::r>() ); // how I would like to use it, how to declare `createx` function?
}
这是我尝试过没有成功的事情:
// that is what I tried, but it could not deduce T and Foo
template<T Foo::*p, class T, class Foo>
X<T, Foo, T Foo::*p> createx()
{
return X<T, Foo, p>();
}
// this works, but requires to write T and Foo explicitly
template<class T, class Foo, T Foo::*p>
X<T, Foo, T Foo::*p> createx()
{
return X<T, Foo, p>();
}
答案 0 :(得分:8)
我不会将成员指针存储为模板参数:
template<class T, class Foo>
struct X {
X(T Foo::*p): p(p) {}
void operator()(Foo & f) {
(f.*p) = 12 * (f.*p); // simple example. could be more complex `operator()`
}
private:
T Foo::*p;
};
template <class T, class Foo>
X<T, Foo> MakeX(T Foo::*p)
{
return p;
}
我认为不可能用你的方法推断出类型:你不能使用指向成员的指针传递给发生类型推导的函数。
修改强> 但是,可能存在基于宏的解决方案。
例如,您可以创建一个类来创建X实例,如下所示:
template <class T, class Foo>
struct XMaker
{
template <T Foo::*p>
X<T, Foo, p> make() { return X<T, Foo, p>(); }
};
现在,您可以创建一个make ...函数来推导T和Foo:
template <class T, class Foo>
XMaker<T, Foo> make_x_maker(T Foo::*)
{
return XMaker<T, Foo>();
}
这使得编写像:
这样的宏成为可能#define CREATE_X(member) make_x_maker(member).make<member>()
用法:
std::for_each(cont.begin(), cont.end(), CREATE_X(&FF::r) );
答案 1 :(得分:1)
如果您希望将任意成员函数指针作为模板参数,我认为不可能减少必须指定的模板参数的数量。
除了成员函数指针之外,您还可以使用普通类型参数来提取引用的仿函数:
template<typename Func>
class X
{
public:
explicit X(Func f = Func()) : f(f) {}
template<class K>
void operator()(K & k) const {
f(k) = 12 * f(k);
}
private:
Func f;
};
然后,您仍然可以选择使用直接访问某个成员的特殊仿函数(如果您认为这可以提供更好的性能),或者使用更通用的访问器仿函数,使用成员函数指针作为成员。
答案 2 :(得分:1)
我有一个问题:你真的需要指定所有这些参数吗?
struct XR
{
template <class Foo>
void operator()(Foo& foo) const { foo.r = 12 * foo.r; }
};
这是有效的,不需要额外的make
方法,它只是起作用:
void testforx()
{
std::vector<FF> cont(5);
std::for_each(cont.begin(), cont.end(), XR());
}
在创建模板时,我不喜欢太通用。
如果你需要一个更复杂的operator()
,你可以随时做一些繁重的工作。
此外,如果您真的希望提取指针函数和对属性的引用,您可以考虑Boost.Bind
。
修改强>:
我有一个想法,这将有点不同,不涉及任何宏观魔法,甚至任何元编程魔法。
为什么不简单地使用typedef并完成它?
好吧,可能没有你想要的那么自动化......毕竟你只需输入一次。
typedef X<int,FF,&FF::m> X_FF_m; // once
std::for_each(cont.begin(), cont.end(), X_FF_m() );
似乎输入的次数少于
std::for_each(cont.begin(), cont.end(), createX<&FF::m>());
一遍又一遍地重复。
我在代码中几乎不使用裸模板,我更喜欢键入它们来提高可读性。