2011-01-19 8 views
3

新しいサイズのstd::arrayタイプを配列のサイズに多態的に使用する方法はありますか?私は、フォーム配列のサイズは共変ですか?

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

そして、それがあるの機能を持っている場合には、ある数学的次の操作を行うために、明確に定義された(それは法的なC++コードではありません場合でも?)このImof

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

数学的にはよく定義されていますが、std::arrayという配列要素が連続し、このコードがコンパイルされるように記述する方法がありますか?私が考えることができる唯一のテクニックは、std::array<T, N+1>std::array<T, N>から継承されている奇妙なテンプレートメタプログラムを持つことですが、配列要素が連続しているとは思えません。

+1

理由だけではなく、テンプレート化ではありません関数をコンパイル時の多態性にしたい場合は 'N 'に、実行時の多形性を望むなら' std :: vector'を使うだけです。 –

+1

@ Karl Knechtel-「少なくとも5つの要素」または「少なくとも10の要素」の配列を常に取り込む関数を作成したいとします。私はテンプレートでこれを行うことができますが、コード全体の重複を招き、 '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 
} 

(あなたがref_array_of_at_leastに、いくつかのoperator[]過負荷などを追加する必要があるだろう、それはそれが正しいの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

これは必要条件だった場合、1つのアプローチが必要な型への変換演算子である:

#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. 

(余分なポイントのために鋳物をクリーンアップ: - /)

関連する問題