C++级联运算符 [] 到运算符 () 参数列表
C++ cascaded operator[] to operator() parameter list?
我有一个这样的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>::type
是std::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);
};
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 具有两个间接寻址运算符 (C++) 的函数参数的用途
- 运算符重载:"operator+"必须采用零个或一个参数
- 为什么数组大小信息可用于"sizeof"运算符和 delete[] 运算符,但在将数组作为参数传递到
- 参数相关查找和流运算符重载
- C++:使用运算符 = 调用多参数构造函数
- 了解布尔运算符==(参数 1,参数 2)
- 我能否根据其运算符()的签名专门化可变参数模板参数
- SFINAE 检查模板参数运算符
- 不允许运算符 const 参数调用 const 成员函数
- 为私有结构定义双参数运算符重载
- C++ 通过自定义赋值运算符隐式转换函数参数
- 函数参数变量总是需要 & 或 * 运算符吗?
- 算术运算符参数类型
- 隐式转换以匹配运算符参数
- 对重载运算符参数执行隐式转换时出现编译器错误
- 避免在C++中强制转换运算符参数
- 如果给定模板不是运算符参数类型的专用模板,则禁用运算符重载
- 以及C++中的运算符参数求值
- 这个函数的运算符参数太多