如何减少模板参数?

时间:2009-11-19 10:02:06

标签: c++ templates

这里我有以下类型的仿函数:

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>();
}

3 个答案:

答案 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>());

一遍又一遍地重复。

我在代码中几乎不使用裸模板,我更喜欢键入它们来提高可读性。