C++级联运算符 [] 到运算符 () 参数列表



我有一个这样的operator()类:

struct S
{
    int operator()(int a, int b, int c, int d);
};

用法示例:

S s;
int i = s(1, 2, 3, 4);

我需要我的用户能够使用替代语法:

int i = s[1][2][3][4]; // equivalent to calling s(1, 2, 3, 4)

我知道我需要添加S::operator[](int a)并且它需要返回一个帮助程序对象。 但除此之外,这一切都变得有点复杂,我有一种感觉,我正在重新发明轮子,因为其他库(例如多维数组(可能已经提供了类似的接口。

理想情况下,我只使用现有的库来实现这一目标。 如果做不到这一点,我如何使用最通用的代码实现我的目标?

编辑:理想情况下,我希望在现代优化编译器上没有任何运行时损失的情况下实现这一目标。

我们开始了!

首先,代码有点混乱 - 我必须随着时间的推移积累参数值,我能想到的唯一方法(至少在 C++03 中(是将设置的即时索引作为数组传递。

我已经在G ++ 4.5.1(Windows/MinGW(上检查过这个,我确认在-O3上调用:

s[1][2][3][4];

生成与以下内容相同的汇编程序代码:

s(1,2,3,4);

所以 - 如果你的编译器在优化方面很聪明,没有运行时开销。干得好,海湾合作委员会团队!

代码如下:

#include <iostream>
template<typename T, unsigned N, unsigned Count>
struct PartialResult
{
    static const int IndicesRemembered = Count-1-N;
    T& t;
    int args[IndicesRemembered];
    PartialResult(T& t, int arg, const int* rest) : t(t) {
        for (int i=0; i<IndicesRemembered-1; ++i) {
            args[i] = rest[i];
        }
        if (IndicesRemembered>0) args[IndicesRemembered-1] = arg;
    }
    PartialResult<T, N-1, Count> operator[](int k) {
        return PartialResult<T, N-1, Count>(t, k, args);
    }
};
template<typename T, unsigned Count>
struct PartialResult<T, 0, Count>
{
    static const int IndicesRemembered = Count-1;
    T& t;
    int args[IndicesRemembered];
    PartialResult(T& t, int arg, const int* rest) : t(t) {
        for (int i=0; i<IndicesRemembered-1; ++i) {
            args[i] = rest[i];
        }
        if (IndicesRemembered>0) args[IndicesRemembered-1] = arg;
    }
    void operator[](int k) {
        int args2[Count];
        for (int i=0; i<Count-1; ++i) {
            args2[i] = args[i];
        }
        args2[Count-1] = k;
        t(args2);
    }
};
template<typename T, unsigned Count>
struct InitialPartialResult : public PartialResult<T, Count-2, Count> {
    InitialPartialResult(T& t, int arg)
        : PartialResult<T, Count-2, Count>(t, arg, 0) {}
};
struct C {
    void operator()(const int (&args)[4]) {
        return operator()(args[0], args[1], args[2], args[3]);
    }
    void operator()(int a, int b, int c, int d) {
       std::cout << a << " " << b << " " << c << " " << d << std::endl;
    }
    InitialPartialResult<C, 4> operator[](int m) {
        return InitialPartialResult<C, 4>(*this, m);
    }
};

说真的,请不要使用它,只是坚持operator(). :)干杯!

这是对bind方法的尝试。我怀疑它是否特别有效,并且它有一些令人讨厌的地方,但我发布它以防有人知道如何修复它。请编辑:

template <int N>
struct Helper {
    function_type<N>::type f;
    explicit Helper(function_type<N>::type f) : f(f) {}
    Helper<N-1> operator[](int p) {
        return Helper<N-1>(bound<N-1>(f,p));
    }
};
template<>
struct Helper<0> {
    function_type<0>::type f;
    explicit Helper(function_type<0>::type f) : f(f) {}
    operator int() {
        return f();
    }
};
Helper<3> S::operator[](int p) {
    return Helper<3>(std::bind(s, _1, _2, _3));
}

其中 s 是返回绑定到 this operator() 的表达式。类似于std::bind(std::mem_fun(S::operator(), this, _1, _2, _3, _4))的东西.虽然我不记得std::bind是否已经可以处理成员函数,但可能不需要mem_fun

function_type<N>::typestd::function<int, [int, ... n times]>bound<N>function_type<N>::type bound(function_type<N+1>::type f, int p) { return std::bind(f, p, _1, _2, ... _N); }。我不确定如何递归定义这些,但你可以将它们列出到一定的限制。

我会完全避免这种情况,只提供operator(),但如果你真的想试一试,这个想法是你的类型的operator[]将返回一个帮助程序类型的对象,该对象既包含对对象的引用,又包含传入的值。该帮助程序类将通过再次存储对原始对象的引用和对 [] 的两个调用的参数来实现operator[]。除了最后一个级别(即相当数量的助手(之外,必须对所有级别执行此操作。我是最后一个级别,operator[]将其参数与所有以前存储的值一起,并使用所有以前存储的值加上当前值调用operator()

一种常见的表述方式是说每个间歇类型将调用的一个参数绑定operator(),最后一个使用所有绑定参数执行调用。

根据您是否希望支持更多或更少的数组维度,您可能希望/需要使其更加复杂以使其通用。一般来说,这不值得付出努力,通常只是提供operator()是解决方案。请记住,最好让事情尽可能简单:更少的写作工作量和维护工作量。

下面是一个支持任意参数和返回类型的 Fusion 实现。 向任何可以做到这一点的人致敬(如果你这样做,请告诉我(!

template <class Derived, class ReturnValue, class Sequence>
struct Bracketeer
{
    typedef ReturnValue result_type;
    typedef boost::fusion::result_of::size<Sequence> Size;
    struct RvBase
    {
        Sequence sequence;
        Derived *derived;
    };
    template <int n>
    struct Rv : RvBase
    {
        Rv(Derived *d) { this->derived = d; }
        Rv(RvBase *p) : RvBase(*p) { }
        Rv<n-1> operator[](typename boost::fusion::result_of::at_c<Sequence const, n-1>::type v)
        {
            boost::fusion::at_c<Size::value - 1 - n>(sequence) = v;
            return Rv<n-1>(this);
        }
    };
    template <>
    struct Rv<0> : RvBase
    {
        Rv(Derived *d) { this->derived = d; }
        Rv(RvBase *p) : RvBase(*p) { }
        ReturnValue operator[](typename boost::fusion::result_of::at_c<Sequence, Size::value - 1>::type v)
        {
            boost::fusion::at_c<Size::value - 1>(sequence) = v;
            return invoke(*derived, sequence);
        }
    };
    Rv<Size::value - 1> operator[](typename boost::fusion::result_of::at_c<Sequence, 0>::type v)
    {
        Rv<Size::value> rv(static_cast<Derived*>(this));
        return rv[v];
    }
};
struct S
    :
    Bracketeer<S, int, boost::fusion::vector<int, int, int, int> >
{
    int operator()(int a, int b, int c, int d);
};

最新更新