2017-05-06 11 views
1

Iは問題がある、私は次のように異なる寸法のシステムに対応するテンプレートクラスを定義:自動生成機能ヘッダ、可変長テンプレート

template <std::size_t N> 
class system { 

    std::array<cv::Mat, N> matrices; 

    ... 

}; 

は、私はに基づいて異なるパラメータを取る異なる関数を定義する必要がありますシステムのサイズそのような何か:

Out-of-line definition of 'fun' does not match any declaration in 'system<3>' 

また、私は、ヘッダー機能は、自動生成テンプレートパラメータNに基づいてされることを希望:

template <> 
template<typename T> 
void system<1>::fun(T & a){ } 

template <> 
template<typename T> 
void system<2>::fun(T & a, T & b){ } 

template <> 
template<typename T> 
void system<3>::fun(T & a, T & b, T & c){ } 

しかししようとしたが、コンパイラは次のエラーを与えるこの戦略を使用しています。私はvariadicテンプレートを使用しようとしましたが、幸運はありませんでした。

+1

私はあなたが達成しようとしていることを100%確信していませんが、このアプローチは間違ったIMOのようです。おそらくコードを自動生成するために何か他の方法を使って運が良いと思うでしょう(例:小さなスクリプト) – UnholySheep

答えて

1

Nに基づいて自動生成できるのであれば、一般的に必要なことを行うためのコードを書くことができると思います(variadicsを使用しようとするあなたのコメントはそのことを補強します)。

あなたの関数もテンプレートでTになっているという事実は、残念ながら私が望むものより少し複雑です。私が与えるより簡単な解決策がありますが、私が見た唯一のものは、型を明示的に指定するか、コンパイル時に実行可能なランタイムチェックを延期することです。それが立っているので、私があなたが望むことをするために見ることができる唯一の方法は、多様なテンプレートを使用することです。これは、あなたが何をしたいの大半を取得します。

template <std::size_t N> 
class System { 

    template <class ... Ts> 
    void fun(Ts& ts) { 
     static_assert(sizeof...(Ts) == N, "Wrong number of parameters!");  
    } 
}; 

私はそれが違いを生むだろう非常に低いですので、あなたが名前の別のメンバ関数を持っていることを計画しない限り、それを場合、有効物事は単純に保つために(とではなく、静的アサートしましたfun ...そうしないでください)。今度は、この関数はN個の引数で呼び出されることだけを受け入れますが、すべての型を変えることができます。あなたはそれらすべてが同じであることを望みます。だから、少しTMPが必要です。

template <class ... Ts> 
struct all_same{}; 

template <class T> 
struct all_same<T> : std::true_type { 
    using same_type = T;  
}; 

template <class T, class ... Ts> 
struct all_same<T, T, Ts...> : all_same<T, Ts...> {}; 

template <class T1, class T2, class ... Ts> 
struct all_same<T1, T2, Ts...> : std::false_type {}; 

一部の古典的な再帰的なTMPでは、私たちが望むものが得られます。パック内のすべてのタイプが同じかどうかの本当の誤ったインジケータと、同じであれば共通タイプにアクセスできます。私たちは共通の型を持っている、とサイズを確認したら、我々はそれ以上の配列とループを初期化するためにパックを使用することができますので、私たちは私たちの関数内で迷惑な可変引数スタイルのプログラミングをやって維持する必要はありません。

template <std::size_t N> 
struct System { 

    template <class ... Ts> 
    void fun(Ts&... ts) { 
     static_assert(sizeof...(Ts) == N, "Wrong number of parameters!"); 
     using same = all_same<Ts...>; 
     static_assert(same::value, "All types must be the same!"); 
     std::array<std::reference_wrapper<typename same::same_type>, N> x{ts...}; 
     for (auto& e : x) { std::cerr << e << std::endl; } 
    } 
}; 

あなたの正確なニーズに合わせてこのソリューションを変更するには、C++の専門知識が必要です。また、特定のトリッキーな状況についても見守る必要があります。文字列リテラルとstd::stringまたは暗黙的に変換可能な他の型の両方を渡すと失敗します。それでも、これがあなたのために役立つことを願っています。ライブ例:http://coliru.stacked-crooked.com/a/08ac23da33deb8ef

+0

これは私が探していた解決策です。 variadicテンプレートを使った私の最初の試みは混乱でした。しかし、私はstd :: reference_wrapperにもっと複雑なテンプレートタイプでいくつか問題があります。いずれにせよ感謝! – thewoz

1

可能な解決策は、クラスの本体内に関数を定義することができる(アンパッサン:名system()を避ける:標準機能と衝突することができる)、SFINAEを使用して、

template <std::size_t N> 
class systemClass 
{ 
    private: 
     std::array<FooType, N> matrices; 

    public: 
     template<typename T, std::size_t M = N> 
     typename std::enable_if<M == 1U>::type fun(T & a) { } 

     template<typename T, std::size_t M = N> 
     typename std::enable_if<M == 2U>::type fun(T & a, T & b) { } 

     template<typename T, std::size_t M = N> 
     typename std::enable_if<M == 3U>::type fun(T & a, T & b, T & c) { } 
}; 

Moreover I would like that the headers functions will be autogenerate based on the template parameter N. I tried to use variadic template but without fortune.

を次のように私はUnholySheepに同意しています。あなたには何を正確にしたいのかは分かりませんが、コードを生成するためのソリューションがシェルスクリプトである可能性があります。

+0

私のご質問はあまり明確ではありません。私はまた、シェルスクリプトが解決策かもしれないと思います。とにかく私もあなたのソリューションが好きですが、異なるfun()関数を指定しないようにするために、@nirソリューションはうまくいきます。 – thewoz

3

integer_sequenceとエイリアステンプレートを使用して、fooをより一般的にすることもできると思います。(integer_sequenceはC++ 14であるが、C++ 11個の実装が同様に存在する):

#include <utility> 
#include <array> 

template <class T, std::size_t> 
using typer = T; 

template <std::size_t N, class = std::make_index_sequence<N>> 
struct S; 

template <std::size_t N, std::size_t... Is> 
struct S<N, std::index_sequence<Is...>>{ 

    std::array<int, N> matrices; 

    template <class T> 
    void foo(typer<const T&, Is>... args) { 
     int dummy[] = { ((matrices[Is] = args), void(), 0)... }; 
     static_cast<void>(dummy); 
    } 
}; 

int main() { 
    S<3> s; 
    s.foo(1, 2, 3); 
} 

[live demo]

+0

これは私の解決策よりも明らかに優れています.Nは知られており、推論する必要はないという事実を利用しています。 –

+0

@NirFriedmanもう一方では、バックグラウンド/エクスペリエンスをインデックス化するconstexprが必要で、一目で分かりにくいかもしれません... –

+1

はい、よりエレガントです。 IMHOそれはあなたがすでにそれを見たなら "明らかです"の静脈にあります。しかし、私は実際にフリー関数にそれを適用するための非常に良い方法を見ていませんでした。実装機能に転送する必要があるようですが、それは正しく機能しないため、むしろ不利になります。 –

1

あなたは、あなたの関数の可変引数を作るが、唯一のパラメータの正しい数を受け入れることができます。パラメータの数がNと等しい場合にのみ機能が存在することを可能にする場合には有効

template <std::size_t N> 
struct system { 
    template<typename... Ts> 
    auto fun(Ts&&... ts) -> std::enable_if_t<(N == sizeof...(Ts))> { 
     // function content 
    } 

private: 
    std::array<cv::Mat, N> matrices; 
}; 

:それは次のようになります。

関連する問題