2017-12-16 28 views
1

テンソルTensorを表すクラスを記述しようとしており、2次元テンソルの場合はtensor(i, j)、3次元テンソルの場合はtensor (i, j, k)というように構文を提供したいと考えています。そしてどのように使用していると言わ引数関数内(マクロva_start va_endとCスタイル以外)int任意の数の引数を受け入れるようにTensor:operator()(int, int, ...)を宣言するためのC++タイプ安全な方法があるかどうか、私は知りたいのは何Variadic関数

です。

お時間をいただきありがとうございます。

+0

何可変引数テンプレートパラメータパックについての完全な実施例でありますか? – user0042

+0

C++バリデーションテンプレートを使用して、引数を特定の型(または特定の型に変換可能)に制限することができます。しかし、得られたパラメータパックを使用することは少し痛みです。 –

+0

テンソルの次元は実行時プロパティか、コンパイル時のものか – StoryTeller

答えて

2

よく、通常のパラメータパックを使用できます。

#include <utility> 
#include <type_traits> 


class foo { 

public: 

    template<typename ...Args, 
     typename=std::void_t<std::enable_if_t 
         <std::is_same_v<Args, int>>...>> 
    void operator()(Args ...args) 
    { 
    } 
}; 

void bar() 
{ 
    foo bar; 

    bar(4, 2); 
} 

コンパイルではなく、これます:これはどちらかのコンパイルされないことに注意してください

bar(4, "foo"); 

または

bar(4, 2.3); 

:すべてのパラメータがintのある場合を除きますが、コンパイルの失敗を強制

unsigned baz=2; 

bar(4, baz); 

符号なしの値を受け入れる必要がある場合は、それに従ってテンプレートをひねります。

受け入れ可能なパラメータは平文であるintであるため、テンプレートは転送参照を使用する必要はありません。テンプレート関数内で、他のパラメータパックを使用するのと同じ方法で使用する、庭の種類の異なるパラメータパックが作成されました。

+1

op 'std :: is_same'の代わりに' std :: is_convertible'かそれに似たものを使うことができます。 – HolyBlackCat

1

intに変換されているにもunsigned intおよび他のタイプを受け入れて、そしてあなたは、整数引数の数に(次の例では63)の上限値を受け入れることができる場合、私はan example from W.F.に従うことを提案します。

ですから、Tensorは、以下の

struct Tensor : public proOp<int> 
{ 
    using proOp<int>::operator(); 
}; 

なる、typer

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

と再帰struct proOpproOp<int>から継承

template <typename T, std::size_t N = 64U, 
      typename = std::make_index_sequence<N>> 
struct proOp; 

template <typename T, std::size_t N, std::size_t... Is> 
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U> 
{ 
    using proOp<T, N-1U>::operator(); 

    void operator() (typer<T, Is>... ts) 
    { } 
}; 

template <typename T> 
struct proOp<T, 0U, std::index_sequence<>> 
{ 
    void operator()() 
    { } 
}; 

を開発することができますが、完全な実施例である

#include <utility> 

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

template <typename T, std::size_t N = 64U, 
      typename = std::make_index_sequence<N>> 
struct proOp; 

template <typename T, std::size_t N, std::size_t... Is> 
struct proOp<T, N, std::index_sequence<Is...>> : public proOp<T, N-1U> 
{ 
    using proOp<T, N-1U>::operator(); 

    void operator() (typer<T, Is>... ts) 
    { } 
}; 

template <typename T> 
struct proOp<T, 0U, std::index_sequence<>> 
{ 
    void operator()() 
    { } 
}; 

struct Tensor : public proOp<int> 
{ 
    using proOp<int>::operator(); 
}; 

int main() 
{ 
    Tensor t; 

    t(1, 2, 3); 
    t(1, 2, 3, 4U); // accept also unsigned 
    //t(1, "two"); // error 
} 
1

もう一つの方法は、operator()は、再帰的にし、

// recursive case 
    template <typename ... Ts> 
    void operator() (int i0, Ts ... is) 
    { 
     // do something with i0 
     this->operator()(is...); // recursion 
    } 

    void operator()() 
    { } 

すべての再帰に次のように最初の引数を使用することができ

struct Tensor 
{ 
    // recursive case 
    template <typename ... Ts> 
    void operator() (int i0, Ts ... is) 
    { 
     // do something with i0 
     this->operator()(is...); // recursion 
    } 

    void operator()() 
    { } 
}; 

int main() 
{ 
    Tensor t; 

    t(1, 2, 3); 
    t(1, 2, 3, 4U); // accept also unsigned 
    //t(1, "two"); // error 
} 
関連する問題