2014-10-19 3 views
3

Что я могу использовать, чтобы сделать функцию, принять N количество аргументов, где N не известно во время программирования, но фиксируется во время компиляции (это параметр шаблона, на самом деле)?Высокопроизводительное решение для принятия N аргументов и возврата значений N

Функция, о которой идет речь, - это функция доступа, которая лежит в критическом пути производительности, поэтому я ищу наименьшие издержки.

Первое, что приходит в голову, это std::initializer_list, и, хотя мне, как мне сказали, по-прежнему остается ненужный объект для создания и копирования. Более того, у него есть забавный способ получить доступ к своим элементам с помощью initializer_list::begin[i] (это еще один объект, который мне не нужен) и не ограничивает количество аргументов N точно, но это незначительная жалоба.

Во-вторых, существуют пакеты параметров шаблонов. Могут ли они быть жизнеспособным кандидатом? Я должен использовать рекурсию для доступа к значениям N.

Что я и добиваюсь я попытался показать в этом псевдо-коде:

template<int dim, class T> class linear_searchspace { 

    template<T...args> operator() (args) { 
     return std::tie(some_kinda_structure[args[0]], some_kinda_structure[args[1]], some_kinda_structure[args[3]]); 
    } 

}; 

Hoow я мог привести его в рекурсивной форме, которая будет работать actualy?

КЛАССИФИКАЦИЯ:args должны быть координатами. Каждая координата является индексом значения в измерении. Таким образом, пройдут N координат, будут возвращены значения N. Это похоже на доступ к N векторам одновременно. Я хотел бы добавить смещение к каждому аргументу, который зависит от индекса аргумента, поскольку он хранит массив с индексом смещения, соответствующим индексу аргумента. Расчет будет простой арифметикой.

И какой будет подходящий тип возврата? Структура, к которой он будет обращаться, скорее всего, будет содержать числовые значения, не более, чем кортежи. Является ли std::tuple лучшим, что я могу сделать, или это возможно сделать что-то более совершенное?

Что касается аргументов, все идет, даже макросы. Я был бы очень рад услышать, какие трюки вы придумали на протяжении многих лет.

+1

Это зависит в значительной степени от того, как вы используете 'arg s'. –

+0

Непонятно, что вы хотите вернуть из функции? Может быть, вектор в порядке, чем initializer_list - ваш друг – Ation

+0

C++ 11 или C++ 14? – Columbo

ответ

2
double data[]={1,2,3,4,5,6,7,8}; 
double& toy_map(int x){return data[x];} 

template<class...Ts> 
auto example(Ts&&...ts) 
-> decltype(std::tie(toy_map(std::forward<Ts>(ts))...)) 
{ 
    static_assert(sizeof...(Ts)==5, "wrong parameter count"); 
    return std::tie(toy_map(std::forward<Ts>(ts))...); 
} 

Обратите внимание, что Заказывайте toy_map называются не определенно.

В C++ 14 удалите строку decltype, если вам не нужен SFINAE.

Замените 5 на N в вашем реальном коде.

Если вы хотите, чтобы перегрузка была идеальной, вам нужно будет SFINAE проверить N, но это обычно является излишним.

+0

'std :: tie' is вероятно, не правильная функция для использования. –

+0

@ t.c. да. Сделанная карта игрушек использует глобальный массив, чтобы сделать его менее глупым. – Yakk

1

Если параметры вашей функции одинаковы, вы можете передать их по вектору. Поместите все данные в вектор, затем передайте вектор функции.

class Coordinate; 

std::vector<Coordinate> my_function(const std::vector<Coordinate>& data) 
{ 
    const unsigned int items_in_data = data.size(); 
    //... 
    return data; 
} 

Вектор является динамичным, и он может рассказать вам, сколько предметов находится внутри него.

Правило большого пальца состоит в том, что когда функция требует много аргументов, поместите аргументы в структуру или контейнер и передайте структуру или контейнер.

+2

Недостаток: распределение на каждый вызов. – Yakk

+1

@Yakk: распределение, только если количество элементов превышает емкость. Векторы и создаются с начальным размером. –

4
template <std::size_t DIM, typename T> 
class linear_searchspace 
{ 
public: 
    template <typename... Args> 
    inline constexpr auto operator()(Args... args) const 
     noexcept(noexcept(T{std::declval<T>()})) 
     -> std::tuple<decltype((void)args, T{std::declval<T>()})...> 
    { 
     static_assert(sizeof...(Args) == DIM, "wrong number of indices!"); 
     using Tuple = std::tuple<decltype((void)args, T{std::declval<T>()})...>; 
     return get<Tuple>(make_index_sequence<sizeof...(Args)>{}, args...); 
    } 

private: 
    template <typename Tuple, typename... Args, std::size_t... Is> 
    inline constexpr Tuple get(index_sequence<Is...>, Args... args) const 
     noexcept(noexcept(T{std::declval<T>()})) 
    { 
     return Tuple((some_kinda_structure[args] + Is)...); 
     //          ^^^^ 
     // some calculation for each element based on index (here simple addition) 
    } 

    T some_kinda_structure[DIM]; // implementation defined 
}; 

(реализация index_sequence находится в демонстрационном)

DEMO

С вышеуказанным раствором один приобретает высокую производительность с constexpr объектами, так как вся операция оценивала при компиляции время:

int main() 
{ 
    constexpr linear_searchspace<5, int> lsp{}; 

    // evaluated at compile-time 
    constexpr auto t = lsp(0, 1, 2, 3, 4); 
    static_assert(std::get<1>(t) == 1, "!"); 

    // evaluated at run-time 
    auto t2 = lsp(4, 3, 2, 1, 0); 
    assert(std::get<3>(t2) == 3); 
} 
+0

Большое спасибо. Теперь я понимаю еще немного :-) – TeaOverflow

Смежные вопросы