2017-01-06 13 views
2

私は、テンプレートの引数として入力の数として符号なし整数をとるクラステンプレートを入力しました。このテンプレートはoperator()をオーバーロードし、Functionは与えられた入力のセットに対して評価することができます。1つのメンバ関数のみを変更するクラステンプレートの特殊化

通常、このメンバーのプロトタイプの1つはoperator()(double, ...)です。しかし、テンプレート引数が0の場合、プロトタイプは機能しません。少なくとも1つの引数が必要です。

template <unsigned Arity> 
struct Function { 
    void operator() (double, ...); 
}; 

通常、私はちょうどテンプレートの特殊化を書くと思いますが、他のメンバ関数がたくさんあるので、冗長なコードのたくさんが存在することになります。繰り返しますが、通常、メインクラスの定義と継承する特殊化のための冗長コードを含む基本クラスを作成します。

struct FunctionBase { 
    // Common code 
    Function operator + (Function const &) const; // ? 
}; 

template <unsigned Arity> 
struct Function : FunctionBase { /* etc */ }; 

operator+ためFunctionを返すように意図されているので残念ながら、私は、これをやって行くのかわかりませんよ。しかし、Functionがあとで定義された場合、どうすればいいですか? 、Function基底クラスから継承し、この設計によりoperator+は、基底クラスである...

それは、基本クラスのインスタンスを返すことができたが、その後、私たちはFunctionのインスタンスにそのインスタンスを変換する方法が必要です最初のインスタンスのデータをコピーせずにこれを行う方法がないことはわかっています。これはパフォーマンス面で非常に高価です。

どうすればこの問題を解決できますか?

+3

C++は難しいですが。あなたが良い提案を得ることを望むなら、あなたの質問にあなたがしたいことの具体例を含める必要があります。特に変更できないすべてのビットを指摘します。これはあまりにも曖昧です。出発点は、「あなたは単一のクラスメソッドを専門化することはできません。クラス全体を専門化する必要があります」。だから回避策を見つける必要があります。最初にいくつかのコードを投稿してください。 –

+1

これは一つの重大な段落です。それに関係なく、クラスを前方宣言し、その型を関数宣言で戻り値の型として使用し、クラスを定義し、関数を定義することができます。 – Quentin

+2

あなたが何を求めているのかは不明です。それを改善するためにあなたの投稿を編集しない限り、それはおそらく閉会に投票されます。 See [ask]。 –

答えて

3

質問は明らかではないので、答えるのはかなり難しいです。
あなたの問題を解決しようとする2つのpossibile選択肢下:

  • あなたはArityテンプレートパラメータを進めるしたい場合は、0に等しいArityに対処するためにsfinae'd演算子を使用することができます。

    #include<iostream> 
    
    template<int Arity> 
    struct Function { 
        template<int N = Arity> 
        std::enable_if_t<N == 0> operator()() { 
         std::cout << "arity == 0" << std::endl; 
        } 
    
        template<int N = Arity> 
        std::enable_if_t<N != 0> operator()(double, ...) { 
         std::cout << "arity != 0" << std::endl; 
        } 
    }; 
    
    int main() { 
        Function<0> f1; 
        Function<2> f2; 
    
        f1(); 
        f2(0., 42); 
    } 
    

    この方法では、基本クラスを導入する必要がなくなり、関連するすべての問題はもう適用されません。

  • あなたの代わりにアプローチを変える気にしている場合、あなたは関数オブジェクトのために、次のパターンに切り替えることができます

    template<typename> 
    struct Function; 
    
    template<typename R, typename... A> 
    struct Function<R(A...)> { 
        R operator()(A... args) { 
         // ... 
        } 
    
        // ... 
    }; 
    

    それは次のようにあなたがそれを使用することができます:

    Function<void(int, char)> f; 
    

    をあなたがしたい場合はoperator()の最初のパラメータとしてdoubleを固定している場合は、これを行うことができます。

    template<typename R, typename... A> 
    struct Function<R(double, A...)> { 
        R operator()(double d, A... args) { 
         // ... 
        } 
    
        // ... 
    }; 
    

    そして、それは次のようにそれを使用する:

    Function<void(double, int, char)> f1; 
    Function<void(double)> f1; 
    

    を。これは、少なくとも空のパラメータパック(sizeof...(A)はあなたにどのような場合でも提出パラメータの数を返すことに注意してください)で簡単に対処するのに役立ちます。

    それは、最小限の作業実装例は以下:

    #include<iostream> 
    
    template<typename> 
    struct Function; 
    
    template<typename R, typename... A> 
    struct Function<R(A...)> { 
        R operator()(A... args) { 
         int _[] = { 0, (std::cout << args << std::endl, 0)... }; 
         (void)_; 
        } 
    
        template<typename... O> 
        Function<R(A..., O...)> operator+(Function<R(O...)>) { 
         return {}; 
        } 
    
        // ... 
    }; 
    
    int main() { 
        Function<void(int)> f1; 
        Function<void(double)> f2; 
    
        f1(42); 
        f2(0.); 
        (f1+f2)(3, .3); 
    } 
    
関連する問題