Как определить и использовать указатель на «массив» член?

У меня есть куча структур, каждая из которых имеет элемент «массив» и индикатор размера:

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

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

Я хочу создать объекты манипулятора для каждой структуры:

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 Позвольте мне управлять элементами массива независимо от того, какое смещение массива и индикатор размера находятся в структурах. Все StructManipulator смещение массива в структуре, смещение и тип индикатора размера и указатель на объект структуры.

Тем не менее, когда я пытаюсь создать StructManipulator:

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

Я получаю эту ошибку:

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);

Похоже, я не мог правильно объявить тип «указатель на член массива»? Какой должна была быть правильная декларация?

1

Решение

Практически те же синтаксические правила, которые применяются к деклараторам указателей, также применяются к указателям на деклараторы членов. Это означает, что elements нужно определить так:

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

В противном случае вы получаете массив указателей на элементы, а не указатель на массив элементов.

И тогда вам лучше заключить в скобки любой доступ через него, как и в случае с другими указателями на члены, которые используются для выражений postfix (таких как вызовы функций):

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

Другие решения

В C ++ 17 вы можете использовать std::invoke вызывать членов класса (не только функции-члены), вместо использования .* а также ->* операторы с их неудобными правилами приоритета.

Итак, для @ StoryTeller’s

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

вы можете получить доступ к массиву, написав

std::invoke(elements, resource_)[idx] = val;
2

По вопросам рекламы [email protected]