2014-10-19 84 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工作?

CLARIFICATION:args應該是座標。每個座標都是維度中值的索引。所以N個座標被傳遞,N個值將被返回。這就像是同時訪問N個向量。我想爲依賴於參數索引的每個參數添加一個偏移量,因爲它存儲的是一個數組,其索引與參數的索引相對應。計算將是簡單的算術。

什麼是適當的返回類型?這個訪問的結構最可能保存數值,元組。 std::tuple是我能做的最好的或者是否可以製造更高性能的東西?

關於參數,什麼都可以,甚至是宏。我很高興聽到你多年來想出了什麼招數。

+1

這很大程度上取決於你如何使用'arg s'。 – 2014-10-19 14:40:15

+0

目前還不清楚你想從功能中返回什麼?也許矢量是好的,比initializer_list是你的朋友 – Ation 2014-10-19 14:45:12

+0

C++ 11或C++ 14? – Columbo 2014-10-19 14:45:50

回答

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中,如果您不需要SFINAE,請刪除decltype行。

用您的真實密碼替換5N

如果你想超載是完美的,你將不得不SFINAE N檢查,但這通常是矯枉過正。

+0

'std :: tie'是可能不是正確的功能使用。 – 2014-10-19 16:01:18

+0

@ t.c。是。製作的玩具地圖使用全局數組來減少愚蠢。 – Yakk 2014-10-19 16:14:59

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 2014-10-19 16:15:25

+1

@Yakk:僅當元素數量超過容量時才分配。矢量並以初始大小創建。 – 2014-10-19 16:16:44

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 2014-10-19 17:33:57