Search code examples
c++templatesc++14pointer-to-memberpointer-to-array

How to define and use a pointer to an "array" member?


I have a bunch of structs, each of which has an 'array' member and a size indicator:

struct S {
    size_t num;
    int arr[100];
};

struct V {
    float array[10];
    int size;
};

I want to create manipulator objects for each struct:

template <typename Type, typename ElementType, size_t N, typename SizeType>
struct StructManipulator {
    Type* resource_;
    ElementType Type::*elements[N];
    SizeType Type::*sizeIndicator;

    void set(ElementType val, size_t idx)
    {
        resource_->*elements[idx] = val;
    }
};

template <typename Type, typename ElementType, size_t N, typename SizeType>
StructManipulator<Type, ElementType, N, SizeType> makeStructManipulator(Type* resource,
        ElementType Type::*elements[N], SizeType Type::*sizeIndicator)
{
    return StructManipulator<Type, ElementType, N, SizeType>{resource, elements, sizeIndicator};
}           

StructManipulator will let me manipulate array elements independent of what the offset of the array and the size indicator are within the structs. All StructManipulator is the offset of the 'array' within a struct, the offset and the type of the size indicator and a pointer to the struct object.

However, when I attempt to create a StructManipulator:

int main()
{
    S s;
    auto m = makeStructManipulator(&s, &S::arr, &S::num);
    m.set(5, 4);
}

I get this error:

main.cpp: In function 'int main()':
main.cpp:39:56: error: no matching function for call to 'makeStructManipulator(S*, int (S::*)[100], size_t S::*)'
     auto m = makeStructManipulator(&s, &S::arr, &S::num);
                                                        ^
main.cpp:29:51: note: candidate: template<class Type, class ElementType, long unsigned int N, class SizeType> StructManipulator<Type, ElementType, N, SizeType> makeStructManipulator(Type*, ElementType Type::**, SizeType Type::*)
 StructManipulator<Type, ElementType, N, SizeType> makeStructManipulator(Type* resource,
                                                   ^~~~~~~~~~~~~~~~~~~~~
main.cpp:29:51: note:   template argument deduction/substitution failed:
main.cpp:39:56: note:   mismatched types 'ElementType Type::**' and 'int (S::*)[100]'
     auto m = makeStructManipulator(&s, &S::arr, &S::num);

I looks like I could not declare the type of the "pointer to an array member" correctly? What should have been the correct declaration?


Solution

  • Pretty much the same syntactic rules that apply for pointer declarators also apply to pointer to member declarators. This means that elements needs to be defined like this:

    ElementType (Type::* elements)[N];
    

    Otherwise you get yourself an array of pointers to members, instead of a pointer to member array.

    And then you better parenthesize any access through it, as you should with other pointers to members that are used for postfix expressions (such as function calls):

    (resource_->*elements)[idx] = val;