none
Generics で四則演算がしたい。 RRS feed

  • 質問

  • 以下のようにGenericsを利用したクラスの中で、四則演算を行いたいのですが、エラーが出てしまいます。何か制約を加えないといけないようなのですが、ヘルプで調べてもさっぱり分かりません。どうすればよろしいのでしょうか。

    class MatrixCalc<TYPE>
        {
            static public TYPE[] Sum(TYPE[,] _Matrix)
            {
                int NumRaw = _Matrix.GetLength(0);
                int NumCol = _Matrix.GetLength(1);

                TYPE[] outvector = new TYPE[NumCol];

                System.Array.Clear(outvector, 0, outvector.Length);

                for (int ri = 0; ri < NumRaw; ri++)
                {
                    for (int ci = 0; ci < NumCol; ci++)
                    {
                        outvector[ci] += _Matrix[ri, ci];//ここでエラーが起こります。内容は下に。
                    }
                }

                return outvector;
            }
        }

    エラー 演算子 '+=' を 'TYPE' と 'TYPE' 型のオペランドに適用することはできません。 

    2006年7月3日 5:55

すべての返信

  •  public delegate T Add<T>( T a, T b );

     class MatrixCalc<TYPE>
     {
      static public TYPE[] Sum( TYPE[ , ] _Matrix, Add<TYPE> add )
      {
       int NumRaw = _Matrix.GetLength( 0 );
       int NumCol = _Matrix.GetLength( 1 );

       TYPE[] outvector = new TYPE[ NumCol ];

       System.Array.Clear( outvector, 0, outvector.Length );

       for( int ri = 0; ri < NumRaw; ri++ )
       {
        for( int ci = 0; ci < NumCol; ci++ )
        {
    //     outvector[ ci ] += _Matrix[ ri, ci ];//ここでエラーが起こります。内容は下に。
         outvector[ ci ] = add( outvector[ ci ], _Matrix[ ri, ci ] );
        }
       }

       return outvector;
      }
     }

     class Program
     {
      static void Main( string[] args )
      {
       int[ , ] matrix = new int[ 3, 5 ];

       MatrixCalc<int> calc = new MatrixCalc<int>();
       int[] ret = MatrixCalc<int>.Sum( matrix, delegate( int a, int b )
       {
        return a + b;
       } );
      }
     }

    こういうのしか思いつきません。つまり使う方が足してやれと。

    もっといい方法があるのかな?

    2006年7月3日 14:19
  • 囚人さん

    ご回答、ありがとうございました。

    この方法で目的は達成できそうですが、すこしややこしくなりそうですね。

    私の使い方がまずいのかもしれませんが、Genericsは使えそうで

    いまひとつ使いづらいです。

    以下のコードでもエラーが出てしまいました。

        class MatrixWriter<T>
        {
            public void Write(BinaryWriter _BWriter, T[,] _data)
            {
                foreach (T onedata in _data)
                {
                    _BWriter.Write(onedata);//ここでエラー
                }
            }
        }

    エラー 1  'System.IO.BinaryWriter.Write(bool)' に最も適しているオーバーロード メソッドには無効な引数がいくつか含まれています。 
    エラー 2  引数 '1': 'T' から 'bool' に変換できません。

     

    ううん、難しい。

    2006年7月3日 14:57
  • ん~と、コンパイラさんがなぜエラーを吐き出すか理解されてます??(^^;

    class Test{}

    というのがあったとして、

    MatrixWriter<Test> matrixWriter = new MatrixWriter<Test>();

    とした場合、どうなるでしょう?
    MatrixCalcのほうも同様です。
    Testクラスに対して += はできないですよね。
    頭の中では、きっとintとかfloatとかパラメータで渡して計算させたいのでしょうけど。(^^;

    2006年7月3日 16:21
  • というかGenericsのなんたるかが判りづらいと思っている人が作るコードにGenericsを適用する局面は無いんじゃないかと。

    通常のクラスでやるけど、これだけはGenericsにすることが可能だよね?という検討を経てやるものだと思います。

    本当にわれわれのようなコードを書くような人間が書く局面は限られています。

    #フレームワーク開発だとかでは使うことになるかもしれません。
    #ただそれらも、Interfaceだけとか、基底クラスで解決できることの方が多いでしょう。

    2006年7月3日 23:19
  • のぶさん、中博俊さん、ご回答ありがとうございました。

    やはり私はGenericsがよくわかっていないようですので、オーバーロードで対応することにしました。まだ本当に勉強段階で、いろいろとやってみたかったのですが、少し難しすぎました。

    どうもありがとうございました。

    2006年7月4日 2:03
  • 以下に一例を掲載します。

    (参考) Using generics for calculations
    http://www.codeproject.com/csharp/genericnumerics.asp

    なお、この問題について私のブログにまとめてみました。

    演算にジェネリックが含まれる場合の対処方法
    http://blogs.wankuma.com/trapemiya/archive/2006/07/06/31783.aspx

    
    interface ICalculator<T>
    {
      T Add(T a, T b);
    }
    
    struct IntCalculator : ICalculator<int>
    {
      public int Add(int a, int b) { return a + b; }
    }
    
    class MatrixCalc<TYPE, C> where TYPE : new()
                  where C : ICalculator<TYPE>, new()
    {  
      static public TYPE[] Sum(TYPE[,] _Matrix)
      {
        C calculator=new C();
        
        int NumRaw = _Matrix.GetLength(0);
        int NumCol = _Matrix.GetLength(1);
    
        TYPE[] outvector = new TYPE[NumCol];
    
        System.Array.Clear(outvector, 0, outvector.Length);
    
        for (int ri = 0; ri < NumRaw; ri++)
        {
          for (int ci = 0; ci < NumCol; ci++)
          {
      //      outvector[ci] += _Matrix[ri, ci];//ここでエラーが起こります。内容は下に。
            outvector[ci] = calculator.Add(outvector[ci], _Matrix[ri, ci]);
          }
        }
    
        return outvector;
      }
    }
    
    
    2006年7月6日 4:25
    モデレータ
  • どうしても、+=が使いたい場合は、以下の感じで。 最後のreturnで返すところの型変換が泥臭いなぁ。(^^;
    
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace ConsoleApplication1
    {
      interface ICalculator2<T>
      {
        T Add(T a, T b);
      }
    
      struct IntCalculator2 : ICalculator2<int>
      {
        public int Add(int a, int b) { return a + b; }
      }
    
      struct Number<T, C>  where C : ICalculator2<T>, new()
      {
        private T _Value;
        private static C calculator = new C();
        
        private Number(T Value)
        {
          this._Value = Value;
        }
    
        public T Value { get { return _Value; } }
    
        public static implicit operator Number<T, C>(T a)
        {
          return new Number<T, C>(a);
        }
        
        public static implicit operator T(Number<T, C> a)
        {
          return a._Value;
        }
    
        public static Number<T, C> operator +(Number<T, C> a, Number<T, C> b)
        {
          return calculator.Add(a.Value, b.Value);
        }
      }
    
      class MatrixCalc2<TYPE, C>  where TYPE : new()
                                  where C : ICalculator2<TYPE>, new()
      {
        static public TYPE[] Sum(TYPE[,] _Matrix)
        {
          int NumRaw = _Matrix.GetLength(0);
          int NumCol = _Matrix.GetLength(1);
    
          Number<TYPE, C>[] outvector = new Number<TYPE, C>[NumCol];
    
          System.Array.Clear(outvector, 0, outvector.Length);
    
          for (int ri = 0; ri < NumRaw; ri++)
          {
            for (int ci = 0; ci < NumCol; ci++)
            {
              outvector[ci] += _Matrix[ri, ci];
            }
          }
    
          TYPE[] arrayRet = new TYPE[NumCol];
    
          for (int ii = 0; ii < NumCol; ii++)
            arrayRet[ii] = outvector[ii].Value;
    
          return arrayRet;
        }
      }
    
    }
    #[i](iはホントは半角)をIdeaに変換するのは困るなぁ・・・。
    
    2006年7月6日 4:39
    モデレータ