2011-01-19 35 views
3

有沒有辦法在數組大小中多態地使用新的std::array類型?也就是說,如果我有形式數組的大小是否協變?

void DoSomething(std::array<int, 5>& myArray) { 
    /* ... */ 
} 

然後就是它的功能數學明確執行以下操作(即使它不是合法的C++代碼嗎?)

std::array<int, 10> arr; 
DoSomething(arr); 

Imof這在數學上是明確定義的,有沒有辦法編寫std::array,使它的數組元素是連續的,並且這段代碼編譯?我能想到的唯一技術將是有一些奇怪的模板元程序,其中std::array<T, N+1>std::array<T, N>繼承,但我不相信迫使數組元素是連續的。

+1

爲什麼不只是模板化的如果你想要編譯時多態性,可以在'N'上運行,或者如果你想要運行時多態性就使用'std :: vector'? –

+1

@Karl Knechtel-假設我想要一個函數,它總是包含「至少五個元素」或「至少十個元素」的數組。我可以使用模板來做到這一點,但是這會導致代碼重複,並且需要'static_assert'-esque代碼,這不夠優雅。我不能用'std :: vector'靜態檢查這個。因此,讓函數獲得一定大小的數組的想法就像是C99靜態大小的數組參數,可以在編譯時進行檢查。 – templatetypedef

+0

我不確定你的例子。具體而言,我不確定我是否明白「數學上明確定義」的含義。在'DoSomething'中,如果你查詢'std :: distance(myArray.begin(),myArray.end())',你期望結果是什麼? '5'還是'10'? –

回答

5

直接?

你可以,但是,使用編譯時多態性,以達到非常類似的東西,你可以寫一個參考的包裝,使得它更容易與代碼工作:

#include <array> 
#include <cstddef> 

template <typename T, std::size_t N> 
struct ref_array_of_at_least 
{ 
    template <std::size_t M> 
    ref_array_of_at_least(T (&a)[M]) 
     : data_(a) 
    { 
     static_assert(M >= N, "Invalid size"); 
    } 

    template <std::size_t M> 
    ref_array_of_at_least(std::array<T, M>& a) 
     : data_(&a[0]) 
    { 
     static_assert(M >= N, "Invalid size"); 
    } 

    T* data_; 
}; 

用作:

void f(ref_array_of_at_least<int, 5>) { } 

int main() 
{ 
    std::array<int, 5> x; 
    std::array<int, 6> y; 
    std::array<int, 4> z; 
    f(x); // ok 
    f(y); // ok 
    f(z); // fail 
} 

(你需要添加一些operator[]過載和對等ref_array_of_at_least,它需要一些工作,使之const正確性,但它是證明你正在尋求什麼樣的可能性開始。)

0

沒有,但你可以僞造它:

// Hide this function however you like: "detail" namespace, use "_detail" 
// in the name, etc.; since it's not part of the public interface. 
void f_detail(int size, int *data) { 
    use(data, /* up to */ data + size); 
} 

int const f_min_len = 5; 

template<int N> 
void f(int (&data)[N]) { 
    static_assert(N >= f_min_len); 
    f_detail(N, data); 
} 

template<int N> 
void f(std::array<int, N> &data) { 
    static_assert(N >= f_min_len); 
    f_detail(N, &data[0]); 
} 

這是一個完整的例子,究竟應該作爲工作呈現。你只需要改變int的數據類型(或者將其設爲模板參數)並根據需要添加const即可。

2

如果這是必須的,一種方法是轉換運營商所需的類型:

#include <iostream> 

template <typename T, int N> 
struct Array 
{ 
    Array() { for (int i = 0; i < N; ++i) x[i] = 0; } 

    template <int N2> 
    operator Array<T, N2>&() 
    { 
     // for safety, static assert that N2 < N... 
     return reinterpret_cast<Array<T, N2>&>(*this); 
    } 

    int size() const { return N; } 
    T x[N]; 

    friend std::ostream& operator<<(std::ostream& os, const Array& a) 
    { 
     os << "[ "; 
     for (int i = 0; i < N; ++i) os << a.x[i] << ' '; 
     return os << ']'; 
    } 
}; 


void f(Array<int, 5>& a) 
{ 
    a.x[a.size() - 1] = -1; 
} 

int main() 
{ 
    Array<int, 10> a; 
    std::cout << a << '\n'; 
    f(a); 
    std::cout << a << '\n'; 
} 

我不會推薦它,但:非常可怕的。更明確的機制似乎少了很多容易出現誤操作,以及更加強大 - 這是隱約像:

template <size_t N2> 
Array<T,N2>& slice(size_t first_index) 
{ 
    return *(Array<T,N2>*)(data() + first_index); 
} 

// usage... 
f(a.slice<5>(3)); // elements 3,4,5,6,7. 

(清理加分鑄: - /)

相關問題