2017-11-02 22 views
0

私は楽しい作業のために書いているコードを取得しようとしています。基本的には、タイプをコンパイル時に生成したいと考えています。私は実際にこれらの線に沿って、いくつかの魔法で具体的なタイプを作成したいのですが、その後コンパイル時のテンプレートテンプレートタイプ

template <std::size_t r, std::size_t c, class T = double> 
class abstract_matrix 
{ 
public: 

    static const std::size_t rows = r; 

    static const std::size_t cols = c; 

    typedef T value_type; 

    typedef T storage_type[rows][cols]; 

    constexpr abstract_matrix(storage_type items) 
    { 
     // I hope it's not needed 
    } 

    storage_type storage; 
}; 

例えば、私はabstract_matrixは以下のようになりたいと思い

constexpr static const int vals[3][3] { 
    { 1, 0, 0 }, 
    { 0, 1, 0 }, 
    { 0, 0, 1 } 
}; 

// do magic here for the vals parameter to make this compile 
using id_3by3 = abstract_matrix<3, 3, vals, int>; 

// use the generated type 
id_3by3 mymatrix; 

auto matrix = mymatrix * ...; 

は、テンプレートにこれらの値「を注入」し、コンパイル時に適切なタイプを生成する方法についての提案がありますか?このタイプのすべては、static,const、およびconstexprです。

ありがとうございます!

+0

行列の値をその型の一部にしたいですか?どうして?なぜ単純に 'abstract_matrix <3, 3, int> id_3by3(vals);'? – Thomas

+0

テンプレートの引数リストに 'vals'を渡したくありません。 'std :: initializer_list'を見てください。彼らは潜在的に修正されているものの、 'constexpr'にいくつかの問題を提示します。 https://stackoverflow.com/questions/15937522/constexpr-array-and-stdinitializer-listを参照してください。 –

+1

はい、実際に要素の値を型の一部にしたくないのですが、それは素早く想像することのできない膨大な数のテンプレートの膨張につながります。特定の次元を超えておそらくあなたはなぜあなたがこれを望んでいると思うのかを説明してください。そうすれば、あなたはそれをしないより有用な答えを得ることができます。 –

答えて

1

動作させることはできますが、考慮する必要があることがいくつかあります。

  1. valsは、型のないパラメータとして渡すことができます。しかし、それはTの後に来る必要があります。それ以外の場合は、パラメータの基本型はわかりません。

    したがって、デフォルト値のTはありません。 Tのデフォルト値はdoubleで、最後の引き数のデフォルト値はnullptrですが、それは乱雑なコードにつながります。

  2. id_3by3の定義は、valsではなく、&valsを使用する必要があります。

  3. constと定義した場合、非タイプのテンプレートパラメータでもそのタイプにconstを使用する必要があります。あなたは行列の内容を変更できるようにしたい場合は、

    template <std::size_t r, std::size_t c, class T, T const(*v)[r][c] > 
    class abstract_matrix { ... }; 
    

    を使用

    const int vals[3][3] { ... }; 
    

    任務は、あなたが使用する必要があります:あなたが使用することを義務付け

    template <std::size_t r, std::size_t c, class T, T (*v)[r][c]> 
    class abstract_matrix { ... }; 
    

    int vals[3][3] { ... }; 
    

ここでの作業プログラムです:

#include <iostream> 
#include <cstdint> 

template <std::size_t r, std::size_t c, class T , T (*v)[r][c]> 
class abstract_matrix 
{ 
public: 

    static const std::size_t rows = r; 

    static const std::size_t cols = c; 

    typedef T value_type; 

    constexpr static T(&vals)[r][c] = *v; 

    constexpr abstract_matrix() 
    { 
    } 
}; 

int vals[3][3] { 
    { 1, 0, 0 }, 
    { 0, 1, 0 }, 
    { 0, 0, 1 } 
}; 

using id_3by3 = abstract_matrix<3, 3, int, &vals>; 

int main() 
{ 
    id_3by3 mymatrix; 

    // Original matrix. 
    for (size_t i = 0; i < id_3by3::rows; ++i) 
    { 
     for (size_t j = 0; j < id_3by3::cols; ++j) 
     { 
     std::cout << id_3by3::vals[i][j] << " "; 
     id_3by3::vals[i][j]++; 
     } 
     std::cout << "\n"; 
    } 
    std::cout << "\n"; 

    // Modified matrix. 
    for (size_t i = 0; i < id_3by3::rows; ++i) 
    { 
     for (size_t j = 0; j < id_3by3::cols; ++j) 
     { 
     std::cout << id_3by3::vals[i][j] << " "; 
     } 
     std::cout << "\n"; 
    } 
} 

出力:

1 0 0 
0 1 0 
0 0 1 

2 1 1 
1 2 1 
1 1 2 

更新、あなたOPのcommment

に応じて、あなたが使用static int vals[3][3] = { ... };を置くことができますが、をしたいタイプ.hファイルを定義し、複数の.cppファイルで使用できるようにする必要があります。

複数の.cppファイルで次の内容の.hファイルを使用することができました。

#pragma once 
#include <cstdint> 

template <std::size_t r, std::size_t c, class T , T (*v)[r][c]> 
class abstract_matrix 
{ 
    public: 

     static const std::size_t rows = r; 

     static const std::size_t cols = c; 

     typedef T value_type; 

     constexpr static T(&vals)[r][c] = *v; 

     constexpr abstract_matrix() 
     { 
     } 
}; 

static int vals[3][3] { 
    { 1, 0, 0 }, 
    { 0, 1, 0 }, 
    { 0, 0, 1 } 
}; 

using id_3by3 = abstract_matrix<3, 3, int, &vals>; 

これは、これらの行を2つの.hファイルに分割しても改善できます。例えば、あなたが使用できます。

abstract_matrix.h:

#pragma once 
#include <cstdint> 

template <std::size_t r, std::size_t c, class T , T (*v)[r][c]> 
class abstract_matrix 
{ 
    public: 

     static const std::size_t rows = r; 

     static const std::size_t cols = c; 

     typedef T value_type; 

     constexpr static T(&vals)[r][c] = *v; 

     constexpr abstract_matrix() 
     { 
     } 
}; 

id_3by3.h:あなたが必要とすることなく、異なる.hファイルにid_3by3に類似した他のタイプを定義することができます

#include "abstract_matrix.h" 

static int vals[3][3] { 
    { 1, 0, 0 }, 
    { 0, 1, 0 }, 
    { 0, 0, 1 } 
}; 

using id_3by3 = abstract_matrix<3, 3, int, &vals>; 

それらのすべてにabstract_matrixの定義を複製します。

+0

恐ろしい!これを私のヘッダーに入れれば、複数のシンボルの定義を避けるにはどうすればいいですか?私は静的、const、constexpr、およびさまざまな組み合わせを試してみましたが、私はそれをコンパイルすることはできません(非型のテンプレートパラメータ)または私は複数の定義とリンカのエラーがあります。 – senseiwa

+0

@senseiwa、答えの更新を参照してください。 –

+0

ありがとう!私がこのコードについて唯一警告しているのは、少なくとも私にとっては、C++ 17以上でコンパイルされているということです。 @senseiwa。 – senseiwa