

以下のテンプレートの関数を、

[code]

    complex<double> c = u16todbm<complex<double> >(10, 32768.0, 0.0);
    
[/code]

と呼ぶと問題なくコンパイルできますが、

[code]

    complex<short> c = u16todbm<complex<short> >(10, 32768.0, 0.0);
    
[/code]

に変更すると、`*`や`+`を使用している行で、

> error: no match for ‘operator*’  
>  error: no match for ‘operator+’

が発生してコンパイルが出来ません。

・呼ばれる側

[code]

    template<typename samp_type>
    samp_type u16todbm(samp_type a, double add, double mul)
    {
      // scale offset
      a = a * mul;
      a = a + add;
    
      return a;
    }
    
[/code]

・呼ぶ側

[code]

    int main(int argc, char* args[])
    {
      complex<short> c = u16todbm<complex<short> >(10, 32768.0, 0.0); // コンパイルエラー
      complex<double> c = u16todbm<complex<double> >(10, 32768.0, 0.0); // コンパイル通る
    }
    
[/code]

complexとdoubleの*や+が定義されていないのか？と思いますが、実装方法がわかりません。  
お教え願えないでしょうか。


CC BY-SA 3.0
2016-11-14T04:28:36.890
30386
2016-11-15T02:04:07.197
2016-11-14T06:17:36.620
18621
19556
question
c++
C++テンプレートでerror: no match for ‘operator+’がでる

[code]

    int a = 1.0;
    
[/code]

とはかけない言語仕様(浮動小数点数を整数へ変換する際に切り捨てや丸めなどいくつかの方法があるため一意に変換することができず暗黙変換が定義されない)なのでcomplex<T>でTが整数型の場合は四則演算可能な型はTへの暗黙変換可能な型に対してしか定義されていない(定義すべきでないから)と思います。complexの定義を見ていないので推測ですが厳密にはTの値を実部と仮定するTからcomplex<T>への暗黙変換が定義されているように思います。  
以上からu16todbmは以下のような使い方が適切だと思います。

[code]

    u16todbm<complex<short>>(10, 32768, 0);
    
[/code]

あえて浮動小数点数を指定したいのであれば整数への変換を明示的に実装したu16todbm相当の別のテンプレート関数を定義すべきと思いますが、実装してみると若干不格好なものになりますね。

[code]

    template<typename samp_type, typename cast_type>
    samp_type u16todbm_cast(samp_type a, double add, double mul)
    {
      a = a * (cast_type)mul;
      a = a + (cast_type)add;
      return a;
    }
    
[/code]

手元にC++環境がなく確認できてませんので間違いなどあった場合はご容赦ください


CC BY-SA 3.0
2016-11-14T06:05:44.073
30388
2016-11-14T06:05:44.073
4417
30386
answer


`short` に (16bit short であるとして)  
\- 32768 を加えると符号付整数オーバーフローは未定義動作であるとか  
\- 0.5 を乗じても精度落ちするとか  
\- `abs()` で `sqrt()` を使っているところで精度落ちしないよう工夫しているコードが  
浮動小数点数しか考慮してないとか

いろいろあって `std::complex` は `float` `double` `long double` しか規定していません。

それら以外の型については unspecified つまり未規定とされています。  
`std::complex<short>` の動作は未規定、つまり  
\- `std::complex<short>` を使うこと自体は間違っていないが  
\- 得られる結果は誰も定義していない、すなわち  
\- 期待通りの結果が得られるかもしれない  
\- 期待はずれの結果が得られるかもしれない

`std::complex<short>` を演算するとコンパイルエラーになるように  
gcc はわざとそういう operator を提供していないんでしょう。

mul/add である double は複素数の実部だけを与えて虚部は 0 でよいということなら

[code]

    template<typename T>
    T u16todbm(T a, double add, double mul) {
        a = a * T(mul);
        a = a + T(add);
        return a;
    }
    
[/code]

でいけます。  
これを `std::complex<short>` に対して使って意味があるかは別問題。  
途中であふれたり精度落ちして期待通りの結果になるとは思えません。

[code]

    int main() {
        std::complex<short> c(1, -2);
        std::cout << u16todbm(c, 1, 2) << std::endl; // おそらく期待通り
        std::cout << u16todbm(c, 0.5, -0.5) << std::endl; // たぶん期待外れ
    }
    
[/code]

joke code でこんなの書いたことはあります。何とか期待通り。

[code]

    int main() {
        std::complex<std::string> a("Hello", "Alice");
        std::complex<std::string> b("World", "Bob");
        std::cout << a+b << std::endl;
    }
    
[/code]


CC BY-SA 3.0
2016-11-14T07:38:30.500
30391
2016-11-15T02:04:07.197
2016-11-15T02:04:07.197
8589
8589
30386
answer