2017-11-23 19 views
1

Eigenの適切なパラメータタイプの控除について。Eigenの適切なテンプレート初期化

Matrix(MatrixXd)またはVector(VectorXd)で初期化できるクラスを作成したいとします。

// roughly 
typedef Matrix<double, Dynamic, 1> VectorXd; 
typedef Matrix<double, Dynamic, Dynamic> MatrixXd; 

私はVectorXdMatrixXdで過負荷に2つのコンストラクタを持ってしようとした場合、私はAmbiguous Constructor callエラーを取得する:問題はMatrixXdVectorXdは、両方の固有でtypedefsであるということです。

#include <iostream> 
#include <Eigen/Dense> 

using namespace std; 
using namespace Eigen; 

class Container { 
public: 
    VectorXd a; 
    MatrixXd b; 

    Container(VectorXd a): a(a), b(MatrixXd::Zero(3,3)) { 
     cout << "Initializing with vector" << endl; 
    } 

    Container(MatrixXd b): a(VectorXd::Zero(3)), b(b) { 
     cout << "Initializing with matrix" << endl; 
    } 
}; 

int main() { 
    Container x(VectorXd::Ones(4)); 
    cout << x.a << endl; 
    cout << x.b << endl; 

    Container y(MatrixXd::Ones(4, 4)); 
    cout << y.a << endl; 
    cout << y.b << endl; 

    return 0; 
} 

私が手に正確なエラー:

は、次の例を考えてみ

main.cpp:23:15: error: call to constructor of 'Container' is ambiguous 
Container x(Matrix<double, Dynamic, 1>::Ones(4)); 
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:13:5: note: candidate constructor 
Container(Matrix<double, Dynamic, 1> a): a(a), b(MatrixXd::Zero(3,3)) { 
^ 
main.cpp:17:5: note: candidate constructor 
Container(Matrix<double, Dynamic, Dynamic> b): a(VectorXd::Zero(3)), b(b) { 

そこで質問です:どのように私は、私が電話をかけたいどのコンストラクタ解決するだろうか?

答えて

1

完璧転送、sfinae制約コンストラクタは、特定のユースケースのために働くん:

template<class T> 
Container(T&& a,decltype(VectorXd{std::forward<T>(a)})* = 0): a(std::forward<T>(a)), b(MatrixXd::Zero(3,3)) {} 

template<class T> 
Container(T&& b,decltype(MatrixXd{std::forward<T>(a)})* = 0): a(VectorXd::Zero(3)), b(std::forward<T>(b)){} 

が、これは任意の行列表現のために働くという保証はありませんので、私は、それ(または同等のもの)を使用しないことをお勧めしたいです将来のEigenバージョンのこれらの表現については、これらの変換は私が知る限り、友好的であることが保証されていないためです。

私はそれが

class Container { 
public: 
    VectorXd a; 
    MatrixXd b; 

    struct DefaultedT{}; 
    static constexpr DefaultedT Defaulted{}; 

    Container(VectorXd a,MatrixXd b): a(std::move(a)), b(std::move(b)) {} 
    Container(VectorXd a,DefaultedT): a(std::move(a)), b(MatrixXd::Zero(3,3)) {} 
    Container(DefaultedT,MatrixXd b): a(VectorXd::Zero(3)), b(std::move(b)) {} 
}; 

int main() { 
    Container x(VectorXd::Ones(4),Container::Defaulted); 
    Container y(Container::Defaulted,MatrixXd::Ones(4, 4)); 
    ... 

か、単に行列式を取って、単一のコンストラクタを記述し、それに応じて初期化ロジックを実行するようなものかもしれない、より賢明な過負荷(実際のユースケースに応じて)を提供する方が良いと思います。..

+0

私は選択肢を好きですが、私は彼らが対処しないと思います質問。私は、最後のオプション(単一のコンストラクタ)が手元の問題に対して最も合理的な解決策であると考えています。私はコンストラクタ(コンテナ(x) 'のフレーバの何か)に型を提供する方法があることを期待していましたが、クラスをテンプレート化しなければ、 – Manbroski

+0

オーバーロードされた関数のテンプレート型の解決のための言語機能はありませんか?それとも、そのような機能が値(例: 'Container ')のテンプレートの種類で機能しないのでしょうか? – Manbroski

+1

@Manbrosky、これは、さまざまな暗黙的な変換をサポートするように設計されています。通常のオーバーロード戦略と矛盾します(一般的な情報については、[here](https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html)を参照してください)。引数型の助けを借りずに確実に関数をオーバーロードすることができます。 –

1

これは非常に貧弱なデザインのようですが、適切な名前のセッターを使用して再訪することを強くお勧めします。たとえば、MatrixXd(4,1)を渡すとどうなりますか?とにかく

、質問に答えるために、あなたが入力天気を検出するために、sfinaeを使用することができますが、コンパイル時にベクトルや行列である:

template<typename Derived> 
Container(const MatrixBase<Derived> &a, typename std::enable_if<Derived::IsVectorAtCompileTime,void*>::type* = 0): a(a), b(MatrixXd::Zero(3,3)) { 
    cout << "Initializing with vector" << endl; 
} 

template<typename Derived> 
Container(const MatrixBase<Derived> &b, typename std::enable_if<!Derived::IsVectorAtCompileTime,void*>::type* =0): a(VectorXd::Zero(3)), b(b) { 
    cout << "Initializing with matrix" << endl; 
} 
関連する問題