0

典型的な関数テンプレートの署名:

template<typename Iterator, typename T>
T fn(Iterator first, Iterator last, T init)
{
    T result;
    // ...
    return result;
}

問題は、次のように呼び出すときです。

std::vector<long> data(1000,1);
fn(data.begin(), data.end(), 0);

または明示的に呼び出すことなく他の方法

fn<std::vector<long>::iterator, long>(data.begin(), data.end(),0);

の場合、 T の型は でありint、 でオーバーフローして悪い結果が生じるリスクがありfnます。

では、どのように特化fnして

fn(data.begin(), data.end(), 0);

明確であり、結果は?Tに設定されます。Iterator::value_type選択肢

template<Iterator>
typename iterator_traits<Iterator>::value_type fn(Iterator first, Iterator last, typename iterator_traits<Iterator>::value_type init)
{
    //...
}

g++/clang++ からのあいまいな呼び出しエラーが発生します。

編集:

私は今私の間違いを見て、上記のコードは以下の @Lightness Races の提案で動作します。助けてくれてありがとう。

4

2 に答える 2

2

単純にロングパスを渡さないのはなぜですか?

fn(data.begin(), data.end(), 0L);

それを超えて、おそらく次のようなことができます:

#include <type_traits>

template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type fn(
   Iterator first,
   Iterator last,
   typename std::iterator_traits<Iterator>::value_type init
);

ライブデモ

ただし、オーバーフローの危険にさらされている方法はよくわかりません。

于 2014-01-09T16:26:25.480 に答える
1

として:

0 is an int
0L is a long

正しい引数を指定してメソッドを呼び出すだけです。

  • 正しいリテラルを直接使用する

なので:

fn(data.begin(), data.end(), 0L);
  • または、中間変数を使用することもできます

なので:

long init = 0; // result in 0L

fn(data.begin(), data.end(), init);
  • または値をキャストすることもできます:

なので:

fn(data.begin(), data.end(), static_cast<long>(0));

fnそれを正しく呼び出すことを避けるために書く1つの方法は

template<typename Iterator>
auto fn(Iterator first, Iterator last, typename std::decay<decltype(*first)>::type init)
    -> typename std::decay<decltype(*first)>::type;
于 2014-01-09T16:18:58.327 に答える