У меня есть куча структур, каждая из которых имеет элемент «массив» и индикатор размера:
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);
Похоже, я не мог правильно объявить тип «указатель на член массива»? Какой должна была быть правильная декларация?
Практически те же синтаксические правила, которые применяются к деклараторам указателей, также применяются к указателям на деклараторы членов. Это означает, что elements
нужно определить так:
ElementType (Type::* elements)[N];
В противном случае вы получаете массив указателей на элементы, а не указатель на массив элементов.
И тогда вам лучше заключить в скобки любой доступ через него, как и в случае с другими указателями на члены, которые используются для выражений postfix (таких как вызовы функций):
(resource_->*elements)[idx] = val;
В C ++ 17 вы можете использовать std::invoke
вызывать членов класса (не только функции-члены), вместо использования .*
а также ->*
операторы с их неудобными правилами приоритета.
Итак, для @ StoryTeller’s
ElementType (Type::* elements)[N];
вы можете получить доступ к массиву, написав
std::invoke(elements, resource_)[idx] = val;