2016-11-24 66 views
3

我對lookup table進行硬編碼。所需的元素數量來自一個包含文件,這個文件可能會在將來的某個時間點發生變化。所以我想在編譯時確保我指定的元素數量確實匹配所需的數量。如何在編譯時檢查查找表是否具有正確的大小?

看一看這段代碼:

#include <array> 

// Assume this comes from some included file 
constexpr size_t elementCount = 5; 

int main() { 
    // This works. 
    const std::array<int, elementCount> lookup { 2, 4, 6, 8, 10 }; 

    // But so does this. 
    const std::array<int, elementCount> lookup2 { 2, 4, 6 }; 

    return 0; 
} 

std::array似乎是非常適合的查詢表,因爲它的大小是固定在編譯時。但是,我不知道如何確保使用正確數量的元素進行初始化。由於aggregate initialization,即使我指定的元素太少,該示例也可以正常編譯。

我想出了以下解決方法,但感覺很醜陋:

#include <array> 

template<class T> std::array<T, 1> makeArray(T e1) { 
    return { e1 }; 
} 

template<class T> std::array<T, 2> makeArray(T e1, T e2) { 
    return { e1, e2 }; 
} 

template<class T> std::array<T, 3> makeArray(T e1, T e2, T e3) { 
    return { e1, e2, e3 }; 
} 

template<class T> std::array<T, 4> makeArray(T e1, T e2, T e3, T e4) { 
    return { e1, e2, e3, e4 }; 
} 

template<class T> std::array<T, 5> makeArray(T e1, T e2, T e3, T e4, T e5) { 
    return { e1, e2, e3, e4, e5 }; 
} 

// ... and so on; these functions would live in some utility header file. 

// Assume this comes from some included file 
constexpr size_t elementCount = 5; 

int main() { 
    // This works. 
    const std::array<int, elementCount> lookup = makeArray(2, 4, 6, 8, 10); 

    // This doesn't. :-) 
    const std::array<int, elementCount> lookup2 = makeArray(2, 4, 6); 

    return 0; 
} 

所以,問題是:有一種優雅的方式,以確保在編譯時說我指定的正確數量查找表的元素我是硬編碼的?請注意,數據類型不需要是std::array;任何時間索引的序列容器都可以。

回答

6

您可以模板化的make_array(類似於make_array從圖書館基本面TS):

template<typename T, typename... Params> 
std::array<T, sizeof...(Params)> make_array(Params&&... ps) { 
    return { std::forward<Params>(ps)... }; 
} 

現在,您只需建立數組:

int main() { 
    // This works. 
    const auto lookup = makeArray<int>(2, 4, 6, 8, 10); 
    static_assert(lookup.size() == elementCount, ""); 


    // This doesn't. :-) 
    const auto lookup2 = makeArray<int>(2, 4, 6); 
    static_assert(lookup2.size() == elementCount, ""); // error 
} 

如果你願意,你可以移動的斷言來你的make_array功能(或爲它製作一個包裝),但是,然後,或許一個名稱更改將按順序:

template<typename T, typename... Params> 
std::array<T, sizeof...(Params)> make_lookup_array(Params&&... ps) { 
    static_assert(sizeof...(Params) == elementCount, "must be equal!"); 
    return { std::forward<Params>(ps)... }; 
} 
+1

這比我的重載要好得多。我沒有意識到有一個make_array函數的技術規範。我想我會堅持「官方」簽名;那麼一旦標準化,我就可以切換到std :: make_array。 –

1

您可以使用可變參數模板

#include <array> 

// Assume this comes from some included file 
constexpr size_t elementCount = 5; 

template<class first, class ... T> 
std::array<first, 1 + sizeof...(T)> makeArray(first e1, T ... rest) { 
    static_assert(1 + sizeof...(T) == elementCount, "Must match elementCount"); 
    return { std::forward<first>(e1), std::forward<T>(rest) ...}; 
} 

int main() { 
    // This works. 
    const auto lookup = makeArray(2, 4, 6, 8, 10); 

    // This doesn't. :-) 
    const auto lookup2 = makeArray(2, 4, 6); 
} 

,您可以嘗試here

編輯:

同時使用class firstclass ... T讓編譯器自動推斷的類型元素。也就是說,makeArray的第一個參數的類型定義爲std::array::value_type

+0

@krzaq由於同時使用了「class first」和「class ... T」。 – Jonas