Commutative property a[i] == i[a]
For a built in type integer array say
int a[10];
int i = 2;
a[i] = 10;
alternatively
i[a] = 10;
because
a[i]
is a postfix expression that is *(a+i)
or *(i+a)
because commutative property of addition.
I want to achieve that for a userdefined type say
class Dummy
{
//
};
Is it possible? If yes then how? If no then why?
EDIT :- I know it is ugly but following code compiles :- g++ -dumpversion 4.3.3
#include <stdio.h>
#include<iostream>
#include <string.h>
#inc开发者_开发问答lude <malloc.h>
using namespace std;
int main()
{
string ArrayS[10];
2[ArrayS] = "ADASD" ;
cout << 2[ArrayS] << endl;
return 0;
}
It is impossible because "operator[]
shall be a non-static member function with exactly one parameter" (standard §13.5.5/1), so you cannot define it such that the first argument is of native scalar type.
(Furthermore, a nonstatic operator overload call is interpreted as a member call, so the first operand cannot be implicitly converted, unlike a free function overload. This is one reason why free function overloads are preferred when possible.)
For better or worse, index[ object ]
is a way to ensure that no operator[]
overload gets called.
However.
"The expression E1[E2]
is identical (by definition) to *((E1)+(E2))
" (§5.2.1) and operator+
can be overloaded so long as one side is not native type. This leaves two options vulnerabilities: the "array" must be a class, or the "index" must be a class or enum
.
You would then have to define a proxy type to hold the result of "addition," which defines an operator*
overload. GCC does not support this, however. I'll look deeper into other platforms and references.
Edit: Ah, §13.6/13 overrides 5.2.1 and declares that, for the sake of interpreting an expression involving class or enumeration type, there are functions T& operator[](std::ptrdiff_t, T*);
and T& operator[](T*, std::ptrdiff_t);
. So that's that.
With C++, nothing is impossible. It is however, a terrible terrible idea. Don't do this.
#include <memory>
#include <stdlib.h>
#include <stdio.h>
void *aligned_malloc( size_t bytes, size_t alignment ) {
void *p = malloc( bytes + alignment ), *pa = reinterpret_cast<void*>( reinterpret_cast<size_t>(p) + alignment &- alignment );
reinterpret_cast<void**>(pa)[-1] = p;
return pa;
}
void aligned_free( void *pa ) {
void *p = reinterpret_cast<void**>(pa)[-1];
free( p );
}
struct SupportReverseIndexer
{
class IndexerReversal
{
static const size_t alignment;
friend struct SupportReverseIndexer;
friend class std::auto_ptr<IndexerReversal>;
struct SupportReverseIndexer* const m_parent;
IndexerReversal(struct SupportReverseIndexer* parent) : m_parent(parent) {}
void* operator new(size_t bytes) { return aligned_malloc(bytes, alignment); }
void operator delete(void* p) { aligned_free(p); }
static struct SupportReverseIndexer* getParent(IndexerReversal* pThis)
{
size_t iThis = reinterpret_cast<size_t>(pThis);
iThis += alignment >> 1;
iThis &= ~(alignment - 1);
return reinterpret_cast<IndexerReversal*>(iThis)->m_parent;
}
public:
operator size_t() { struct SupportReverseIndexer* const parent = getParent(this); return parent->indexer(this-parent->ir.get()); }
};
SupportReverseIndexer() : ir(new IndexerReversal(this)) {}
operator IndexerReversal*() { return ir.get(); }
private:
std::auto_ptr<IndexerReversal> ir;
size_t indexer(size_t index) { printf("Custom operator[] called, index = %i\n", index); return index; }
};
const size_t SupportReverseIndexer::IndexerReversal::alignment = 0x10000 * sizeof(SupportReverseIndexer::IndexerReversal);
int main(void)
{
SupportReverseIndexer sri;
int a = sri[2];
a = 3[sri];
a = (-5)[sri];
return 0;
}
No, really, DON'T DO THIS!!!!!
It is completely impossible to do. Potatoswatter correctly points out you couldn't possibly define any operator such as operator[](int, T)
, so overloading for an integer on the left is impossible.
But consider that this works:
struct foo
{
operator const foo*() const
{
return this;
}
};
int main()
{
foo f;
5[f]; // UB
}
Is there a way to utilize this? No:
5.2.1 Subscripting
A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall have the type “pointer to T” and the other shall have enumeration or integral type. The result is an lvalue of type “T.” The type “T” shall be a completely-defined object type.56) The expressionE1[E2]
is identical (by definition) to*((E1)+(E2))
.
With E1
being an integral type, E2
must be a pointer type. So we can't inject user-behavior there.
The only thing left is +
and *
. We can't change operator+
for an integral type and a pointer, because that's defined by the language. The result of E1 + E2
is going to be a pointer, and we can't define operator*
for a pointer either.
Therefore, injecting user-defined behavior is impossible.
a[i] = 10;
i[a] = 10;
because a[i] is a postfix expression that is *(a+i) or *(i+a) because commutative property of addition.
Yes. But a[i] == i[a] == *(a+i) == *(i+a)
is because the notation a[i]
in C is a syntactic sugar for the latter pointer arithmetic. Keyword here "in C". C++ in large tries to part ways from the pointer arithmetic. Thus the a[i]
as a syntactic sugar is only supported on the POD for backward compatibility with the C. But that does not work on any C++ objects since the operations []
has clear semantic specified and it doesn't allow the C-like syntax tricks.
In the end, do not do it. The trick is an obscure remnant of the older times and doesn't have a single good reason to be reincarnated.
Any Dummy that was declared and used as an array will work the same way, if Dummy can be implicitly cast to an integer.
You will need to define the Dummy::operator[](const Dummy& ref)
to exhibit the desired property. For instance:
#include <iostream>
class dummy
{
public:
int operator[](const dummy& ref) { return 0; }
};
int main(int argc, char *argv[])
{
dummy d1, d2;
std::cout << (d1[d2] == d2[d1] ? "Yes" : "No");
}
Of course this is probably not exactly what you're looking for, but the tricky bit will be to replace the return 0;
and possibly the return type with something that you have to define and that satisfies your intent.
Why exactly would you want this? Is it just a mental exercise?
精彩评论