Question

I am coming back to C++ (or well, technically, Objective-C++) after many years absence, so please bear with me. I am trying to use templates to implement a solution that would otherwise require a ton of cut-and-paste code. The excerpt below shows the basic gist of the effort:

namespace {

    using vMAT::DOUBLE;
    using vMAT::SINGLE;
    using vMAT::INT8;
    using vMAT::UINT8;
    using vMAT::INT16;
    using vMAT::UINT16;
    using vMAT::INT32;
    using vMAT::UINT32;
    using vMAT::INT64;
    using vMAT::UINT64;

    typedef void (* swapFn)(void * vector, vDSP_Length vectorLength);

    // Functor used for template arguments.
    template <typename TypeA>
    struct swapbytes {
        swapFn fn;

        swapbytes()
        {
            if      (sizeof(TypeA) == 8) fn = vMAT_byteswap64;
            else if (sizeof(TypeA) == 4) fn = vMAT_byteswap32;
            else if (sizeof(TypeA) == 2) fn = vMAT_byteswap16;
            else if (sizeof(TypeA) == 1) fn = NULL;
            else NSCAssert(NO, @"Oops!");
        }

        void operator()(void * vector, vDSP_Length vectorLength) const
        // ..................................................... ^^^^^ Why?
        {
            if (fn != NULL) fn(vector, vectorLength);
        }
    };

    template <typename TypeA, typename ClassB>
    void
    loadFromOperation(vMAT_MATv5NumericArray * self,
                      vMAT_MATv5ReadOperation * operation,
                      TypeA a,
                      ClassB b)
    {
        swapbytes<TypeA> SwapA;
        long lenC = self.size[0] * sizeof(TypeA);
        TypeA * C = (TypeA *)malloc(lenC);
        long lenD = vMAT_Size_prod(self.size) * sizeof(ClassB);
        self.arrayData = [NSMutableData dataWithCapacity:lenD];
        self.arrayData.length = lenD;
        ClassB * D = (ClassB *)[self.arrayData mutableBytes];
        __block long idxD = 0;
        vMAT_Size123Iterator(self.size, ^(int32_t n, int32_t o, int32_t p) {
            [operation readComplete:C
                             length:lenC];
            if (operation.swapBytes) { SwapA((void *)C, lenC / sizeof(TypeA)); }
            for (int m = 0;
                 m < self.size[0];
                 m++) {
                D[idxD] = C[m];
                ++idxD;
            }
        });
        free(C);
    }

}

- (void)_load_miUINT8_mxDOUBLE_fromOperation:(vMAT_MATv5ReadOperation *)operation;
{
    loadFromOperation(self, operation, UINT8, DOUBLE);
}

My question, as I hope is apparent from the comment ending with "Why?", is why is the const declaration required here? If it is elided, the compiler complains that there is no method signature matching the call site at SwapA(...) in the body of loadFromOperation.

I would understand this if SwapA were explicitly declared as const, but it's not. Obviously it could be, since its operation doesn't rely on mutating any state, but that's beside the point.

And while I have another helpful pair of eyes on this code, I'd welcome any style or other critiques a more proficient C++ practitioner might care to offer…

Was it helpful?

Solution

Non-__block variables that are captured by a block, are copied into the block by value when the block is created, and are const inside the block. i.e. inside the block, SwapA has the type const swapbytes<TypeA>.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top