2016-11-08 7 views
1

Позволяет определить входы:Как развернуть целочисленную последовательность на индексный оператор в C++ 11?

double values[2][2]...[2] N times 
bool signs[N]; 

, что я хочу сделать, это написать функцию шаблона для чего-то вроде этого:

auto result = values[signs[0]][signs[1]]...[signs[N - 1]]; 

К сожалению, не складывая выражения C++ 17, я не могу реализовать что.

Я уверен, что мне нужно использовать std::index_sequence<> в некотором роде:

template <std::size_t ... indices> 
double get_value(const dimension_creator_t<sizeof...(indices)>& values, 
       index_sequence<indices...>, bool (&signs)[sizeof...(indices)]) 

, но не уверен, как поступить. Я могу найти код std::integer_sequence онлайн. dimension_creator_t является псевдонимом для типа values.

Как реализовать желаемую функциональность?

ответ

3

Следующее должно работать, хотя я использовал некоторую свободу, используя вместо этого std::array. Это немного более удобно.

Каждый вызов value_getter<size,I>::get<T> принимает std::array<T,2> в качестве аргумента и обрезает на основе signs[I] таким образом мы получаем arr[signs[I] типа T, который снова Вложенный массив (если я! = Размер), поэтому мы снова называем value_getter<size,I>::get с T в качестве аргумента.

Помощник value_getter struct, чтобы обрезать вложенные массивы по частям.

template <std::size_t size, std::size_t I> struct value_getter { 
template <typename T> 
    static double& get(std::array<T,2>& arr, const std::array<bool, size>& signs) { 
     return value_getter<size, I+1>::template get(arr[signs[I]], signs); 
    } 
}; 

Конечный базовый футляр, возвращающий ссылку на стоимость.

template <std::size_t size> struct value_getter<size, size> { 
    static template <typename T> double& get(T& arr, const std::array<bool, size>& signs) { 
     return arr; 
    } 
}; 

Использование:

std::array< std::array< std::array< double, 2>, 2>, 2> values{}; 
std::array<bool, 3> signs{}; 

double v = value_getter<3,0>::template get(values, signs); 

Demo

Я размышлял о том, как заставить его работать со стилем массива C, хотя, проблема заключается в том, чтобы представить тип std::array<T,2> в функции ::get , Его можно заставить работать чем-то вроде std::add_pointer<T>, который должен дать T* от T.

Так что на самом деле это намного проще в массивах стилей C.

Здесь T будет обозначать сам массив. Если мы обходим какую-либо статическую проверку ошибок, T в основном не используется как тип. Поскольку мы знаем, что arr типа T является массивом (если I != size), то мы всегда можем позвонить operator[] по адресу arr.

template <std::size_t size, std::size_t I> struct value_getter { 
template <typename T> 
    static double& get(T arr, bool *signs) { 
     return value_getter<size, I+1>::template get(arr[signs[I]], signs); 
    } 
}; 

Базовый корпус снова тривиален.

template <std::size_t size> struct value_getter<size, size> { 
    static double& get(double& arr, bool * signs) { 
     return arr; 
    } 
}; 

Demo(C array)