The overloaded operator() is likely to be expanded in-line, so it may not be the performance issue you believe. Have you checked on this?
To be a devil's advocate, the array.p[i][j][k] approach has the advantage of letting you write with array syntax rather than function syntax. Also instead of making your internal pointer public, you should provide an inline getter that would return a T*** const, so the outside code couldn't actually alter your pointer.
My thought is to do this "old style". It should be close to what the compiler would produce for a built-in 3d array. You could also choose between column major and row major order, which might make a difference in some situations.
Your fragment would be revised like so:
template<class T>
class array
{
public:
array( size_t d1, size_t d2, size_t d3) : d1_(d1), d2_(d2), d3_(d3)
{
p = new T[ d1 * d2 * d3 ];
}
public:
T& operator()( size_t x, size_t y, size_t z )
{
return p + (( x * d2_ + y ) * d3_ + z );
}
private:
T *p;
size_t d1_;
size_t d2_;
size_t d3_;
};
Addendum:
Applying table lookup here never occurred to me. Thank you for the idea, aspdotnetdev.
Note that an array lookup might typically be implemented as a multiply and an add. I count 3 multiplies and 3 adds for a 3-d array indexing operation whether it is the OP's, aspdotnetdev's, or my approach. However, depending on the size of T, one of those might very well be replaceable by a bit shift in each of those approaches. In addition, the other 2 multiplies could also be turned into shifts for either the OP's or aspdotnetdev's suggestion, but not mine. So for array index calculations my suggestion is the loser when bit shifts are faster than multiplies.
On the other hand, for locality of reference, I believe that mine is best and the OP's the worst. This can have a significant impact, but depends on the platform and how things are used. The only way to determine that would be by measuring actual performance.
Maybe it is time to do some profiling?