2016-08-05 4 views
2

私はMatrixクラスを持っていると私は二つの方法で私のマトリックスオブジェクトを初期化したいとします2つのオーバーロードされた関数をネストされていないネストされたinitializer_listの引数で区別する方法?

Matrix a = {1,2,3} // for a row vector 

Matrix b = {{1,2,3},{4,5,6},{7,8,9}} // for a matrix 

その結果、私は

以下のように2つのコピーコンストラクタを実装しました
class Matrix { 
private: 
    size_t rows, cols; 
    double* mat; 
public: 
    Matrix() {} 
    Matrix(initializer_list<double> row_vector) { ... } 
    Matrix(initializer_list< initializer_list<double> > matrix) { ... } 
    ... 
} 

explicitキーワードを追加する、または入れ子になったバージョンをMatrix(initializer_list< vector<double> > matrix)に変更するなど、私のインターフェイスをどのように変更しても問題ありません。それは、常にこの2つのケースの間のあいまいさを引き起こします:

Matrix a = {1,2,3};n 
Matrix b = {{1}, {2}, {3}}; 

私が直接/コピー初期化または暗黙の型変換のようなものとはかなり精通していませんよ。この問題の解決策はありますか?

+0

入力に基づいてマトリクスサイズを調整しようとしていますか?例えば、 '{1,2,3}'が3x1ベクトルを生成し、 '{{1,2,3}、{4,5,6}、{7,8,9}}'が生成すると期待しますか? 3x3行列? –

+0

@JonathanMee絶対に。 – pedim

+0

@pedimだから、Visual Studio *を使用すると、3番目のコンストラクタを選択することになります。私はここでそれについての質問を開いた:http://stackoverflow.com/q/38795374/2642059 –

答えて

2

さて、ここで非常に汚いトリックです:

#include <iostream> 
#include <initializer_list> 

struct Matrix 
{ 
    template<class = void> Matrix(std::initializer_list<double>) { std::cout << "vector\n"; } 
    Matrix(std::initializer_list<std::initializer_list<double>>) { std::cout << "matrix\n"; } 
}; 

int main() 
{ 
    Matrix a = {1, 2, 3}; 
    Matrix b = {{1}, {2}, {3}}; 
    (void)a; (void)b; 
} 

2つのオーバーロードは、変換に基づいて区別することはできませんので、我々は、オーバーロードの解決プロセスの次のステップに依存している:非テンプレート関数が好まれますテンプレートの特殊化。

+1

_Disgraceful!_私はそれが大好きです。私は名前のないテンプレートの引数が許されているということも考えていませんでした。私はこの種のものを使ったことはありませんでしたので、ありがたいことに... _yet_。 ;-) –

0

マトリックスを取る1つのコンストラクタを作成するだけではなく、プライベート関数のコピーを作成し、内側のコピーでrow_vectorをチェックするのはなぜですか。

private void Matrix::copy(const Matrix &matrix) 
{ 
    if (matrix.rows == 1) 
    { 
     //row vector stuff here 
    } 
    else if (matrix.cols == 1) 
    { 
     //col vector stuff here 
    } 
    else 
    { 
     //matrix stuff here 
    } 
} 
+0

しかし私の目的は2種類のイニシャライザを受け取ることです。どのようにして、1つのコンストラクタのみを使用して2種類のオブジェクトを扱うことができますか? – pedim

+0

なぜこのような行ベクトルを初期化しないのですか? 行列a = {{1,2,3}} コンストラクタの1つが不要になります。 – Richard

+0

OPは便宜のために2つの異なるタイプの引数を受け取ることができたいと考えています。これは、要求された引数型を区別せず、このプライベート関数がどのように使用され/有用であるかを説明する努力はしません。とにかくコンパイルさえしません:コロン(および改行)を忘れてしまったり、 Java/C#について考え直してください。 –

4

いずれの場合でも明白に機能する解決法はありません。ただし、ケースを明確にする方法を作成することができます。

template<typename T> 
auto il(std::initializer_list<T> the_il) -> std::initializer_list<T> { return the_il; } 

Matrix b = {il({1}), {2}, {3}}; 

しかし、私はあなたがそれについて明示することを個人的に提案します。ユーザーが1つの行を含む行列を望んでいるなら、それは一つの行を含むマトリックスようになっているはずです、ベクトルを好きではない:

Matrix a = {{1,2,3}}; 

だから私は完全に最初のオーバーロードを捨てることをお勧め。

関連する問題