2016-11-02 16 views
1

私はそれがかなり一般的なタイトルだと知っていますが、私はいくつかのコードを持っていて、それは私がコンパイルできない奇妙なものです。このコードはなぜコンパイルに失敗しますか?

Hereは、この問題のデモです。 scalar_tdoubleからfloatに変更するとコードが正常にコンパイルされます。なぜここで倍増することができないのですか?実際に、定数をdouble1.0)またはint1)に変更すると、それらも昇格できません。これはちょうどうまくいくべきものなのでしょうか?

完全なコードサンプル:

#include <valarray> 
#include <numeric> 
#include <iterator> 
#include <iostream> 

template<typename T> 
T sigmoid(const T &in) 
{ 
    return 1.f/(1.f + std::exp(-in)); 
} 

template<typename T> 
T logit(const T &in) 
{ 
    return std::log(in/(1.f - in)); 
} 

using scalar_t = double; 

int main(int argc, char **argv) 
{ 
    std::valarray<scalar_t> f = { 0.1f, 0.3f, 0.5f, 0.9f }; 

    scalar_t alpha = 0.5f; 
    scalar_t beta = -1.f; 

    auto lC = logit(f);  
    std::valarray<scalar_t> skC = alpha * lC + beta; 
    auto sC = sigmoid(skC); 

    std::copy(std::begin(sC), std::end(sC), std::ostream_iterator<scalar_t>(std::cout, " ")); 
    std::cout << std::endl; 

    scalar_t num = 0.7f; 
    auto lS = logit(num); 
    auto sS = sigmoid(alpha * lS + beta); 

    std::cout << sS << std::endl; 

    return 0; 
} 
+0

プロモーションに問題はありません。 'valarray'の' operator-'は、左辺(' T const& ')と右辺(' valarray const& ')の両方について同じ型を推論します。同じテンプレート引数に対して 'float'と' double'の両方を取得するので、競合します。 '1.0'を実行することで修正できるはずです。 – 0x499602D2

+0

「なぜここで二重にすることができないのですか?あなたのコードのどの特定のポイントを "ここ"と呼んでいますか?あなたは何の宣伝をしていますか? – AnT

+0

@ 0x499602D2あなたは正しいですが、ここで暗黙的な変換が行われるべきではないのはなぜですか?私は本当に1を行うことによってそれを修正することはできません。私が 'scalar_t'の知識を持っていない(またはこの議論ではないと仮定して) –

答えて

4

operator -これは、それがvalvalarray内の要素と同じタイプであることを期待しているMEAS

template <class T> std::valarray<T> operator- (const T& val, const std::valarray<T>& rhs); 

としてあなたが定義されて使用されています。テンプレート引数の差し引きが発生したときに floatを使用しているので、 valfloatですが、 rhsの要素タイプは doubleです。これらの型は一致しないため、控除に失敗し、コンパイラエラーが発生します。テンプレート引数の控除中に変換が行われないことを忘れないでください。

+0

「テンプレート引数の控除中に変換が起こらない」と私は問題だと思います。だから明らかな次の質問は、私が 'scalar_t'について知らないと仮定して、どうすれば修正できるのでしょうか?このシナリオで暗黙的な変換が許可されるべきでもない理由は? –

+0

@ MaxEhrlich最も単純なのは、リテラルを 'scalar_t'に変換することです。関数が標準型に対してのみ使用される場合は、常に 'value_type'メンバを使用してその型にリテラルをキャストできます。 – NathanOliver

+0

これはこのサンプルでは解決しますが、 'scalar_t'の知識がなく、' T'の型に関する知識が全くないと仮定します(私が 'scalar_t' 'valarray 'は両方とも暗黙の暗黙の変換を除いて正常に動作するはずです) –

1

これは、これらのタイプに依存しないテンプレートで定数を使用する方法について非常に興味深い議論を生み出しました。意外にも答えがあるようです。 sigmoid関数を調べると、floatの定数をvalarray<double>と使用していることがわかりますが、コンパイラエラーは発生しません。これは、std::exp(-in)行がvalarray<double>を標準ライブラリで使用されている式テンプレートに変換して計算を最適化し、何らかの理由でfloatまたはdoubleを気にしない(たとえば、オーバーロードを提供する)ためです。だから、私が思いついた解決策は、定数で動作する式テンプレートにvalarray<double>を変換する以外は絶対に何もしないで、logit関数に単項演算子+演算子を追加することでした。単項+演算子(+in)

がまた尋ねたとしてNathanOliverの受け入れソリューションは、質問に答えることに注意してください

Hereは、更新コードサンプル

で、新しいlogit機能は、この

template<typename T> 
T logit(const T &in) 
{ 
    return std::log(in/(1.f - (+in))); 
} 

ノートのように見えます

関連する問題