6

私は最近 C++11 をいじっていて、次の sum 関数を思いつきました:

template <typename T>
inline T sum(const std::function<T (int)> &f, int initial, int end)
{
    T retval = 0;
    for(int k = initial; k <= end; k++) {
        retval += f(k);
    }
    return retval;
}

アイデアは、ラムダ関数を渡すことができるため、数学的な合計のためのきちんとした読みやすい関数を持つことができるということです。次に、次のことを試しました。

int main()
{
    std::array<double, 2> arr1 = {{ 0.5, 1.5 }},
                          arr2 = {{ 1.5, -0.5 }};
    auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss!
                      0, 1);
    return 0;
}

これを g++ 4.6.3: を使用してコンパイルしg++ -Wall -pedantic -std=c++0x -o test main.cppましたが、ソース コードのコメントで指摘した精度の低下に関する警告は表示されません。

ここでsum<int>は、悪いことをするのはほとんど当然のことですが、より複雑な状況ではそれほど明白ではないかもしれません。コンパイラはラムダ関数の戻り値doubleintそれができない特定の理由はありますか?

4

3 に答える 3

2

VS11 は警告を発行します。

警告 1 警告 C4189: 'n': ローカル変数は初期化されていますが、参照されていません
警告 2 警告 C4244: '+=': 'double' から 'int' への変換、データが失われる可能性があります

編集、実際にはその警告はコードの使用によるものです:

template <typename T,typename Func>
inline T sum(Func f, int initial, int end)

を使用すると、不正な変換に関する別の警告が表示std::function<T (int)>されるため、VS はこの問題に引き続き適しています。(IMO、通常、ファンクターは std::function ではなくテンプレート化された型として使用する必要があります)

-Weverything を使用して clang を実行しても、これに関する警告は表示されません (編集: std::function バージョンを clang ATM でテストすることはできませんが)。改善できるもののようです。

ただし、この奇妙な警告が表示されます。

ConsoleApplication1.cpp:15:51: warning: will never be executed [-Wunreachable-code]
    auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss!
                                                  ^~~~
于 2012-04-12T13:28:00.180 に答える
1

retval += f(k);ファンクターの制約を解除し、行を次のように変更した場合retval += T { f(k) };:

// Machinery to allow caller to indifferently use
// sum(f, i, j) and sum<R>(f, i, j)
struct deduced {};

template<
    typename Request = deduced
    , typename Functor
    , typename Ret = typename std::conditional<
        std::is_same<Request, deduced>::value
        , typename std::result_of<Functor&(int)>::type
        , Request
    >::type
>
inline Ret sum(Functor f, int initial, int end)
{
    Ret retval = 0;
    for(int k = initial; k <= end; k++) {
        retval += Ret { f(k) };
    }
    return retval;
}

次に、コンパイラの警告の意思に依存する代わりに、リストの初期化 (つまり、中括弧による初期化) 内で縮小変換が許可されていないため、診断を発行する必要があります。

ファンクタを に制約する場合、信頼できる方法はないと思いますstd::function<Sig>std::functionそれは、実装がどのように を記述したか、縮小変換の警告をいつ発行するか、さらには独自のコードに対して警告するかどうかにのみ依存します。

于 2012-04-12T14:20:06.827 に答える