Ответ 1
template<class T, int...Shape>
class Array {
template<int>using index_t=int; // can change this
public:
T& operator()(index_t<Shape>... is);
};
или
template<class T, int...Shape>
class Array {
public:
T& operator()(decltype(Shape)... is);
};
или
template<class T, int...Shape>
class Array {
public:
T& operator()(decltype(Shape, int())... is);
};
если вы хотите изменить тип параметра, отличающийся от Shape
.
Я считаю, что decltype
сложнее понять прикосновение, чем using
, особенно если вы хотите изменить тип параметра, отличный от int
.
Другой подход:
template<class T, int...Shape>
class Array {
public:
template<class...Args,class=typename std::enable_if<sizeof...(Args)==sizeof...(Shape)>::type>
T& operator()(Args&&... is);
};
который использует SFINAE. Он не гарантирует, что Args
являются целыми типами. Мы могли бы добавить другое предложение, если бы захотели (чтобы все Args
были конвертированы в int
, скажем).
Еще один подход заключается в том, чтобы ваш operator()
принял пакет значений, например a std::array<sizeof...(Shape), int>
. Вызывающие должны:
Array<double, 3,2,1> arr;
arr({0,0,0});
используйте набор {}
s.
Окончательный подход:
template<class T, int...Shape>
class Array {
public:
template<class...Args>
auto operator()(Args&&... is) {
static_assert( sizeof...(Args)==sizeof...(Shapes), "wrong number of array indexes" );
}
};
где мы принимаем что-либо, а затем генерируем ошибки, если это неправильное количество аргументов. Это генерирует очень чистые ошибки, но не выполняет надлежащую перегрузку оператора SFINAE.
Я бы порекомендовал отправку тегов, но я не вижу способа сделать его намного более чистым, чем решение SFINAE, с дополнительными decltype
и всеми или более эффективными сообщениями об ошибках, чем версия static_assert
, с другой стороны.