1

次のような関数があるとします。

template <class In, class In2>
void func(In first, In last, In2 first2);

この関数で、述語を受け入れる別の関数を呼び出したいと思います。私の最初の本能は、次のようなことをすることでした:

template <class In, class In2>
void func(In first, In last, In2 first2) {
    typedef typename std::iterator_traits<In>::value_type T;
    other_func(first, last, first2, std::less<T>());
}

Inしかし、In2イテレータが異なる型の場合はどうなるでしょうか? たとえば、char*int*Inどちらが述語でどちらが述語であるかに応じてIn2、比較中に値が切り捨てられる場合があります。たとえば、 if Inis char*thenは、 is でstd::less<char>あっても呼び出されます。In2int*

::operator<2 つのパラメーターを指定すると、コンパイラは正しい型を推測でき、標準の型昇格規則が適用されます。ただし、関数に渡す述語を選択する場合、これが発生する機会はありません。とに基づいて、どのバージョンを渡したいかを判断する賢い方法はありますか?std::less<>InIn2

編集:

次の例は、この問題を示しています。

unsigned int x = 0x80000000;
unsigned char y = 1;
std::cout << std::less<unsigned char>()(x, y) << std::endl;
std::cout << std::less<unsigned int>()(x, y) << std::endl;

出力します:

1
0

編集

それについて考えた後、私が本当に欲しいのは、次のようなことができるようになることです:

typedef typeof(T1() < T2()) T;
other_func(first, last, first2, std::less<T>());

gcc の__typeof__拡張機能を使用できると思いますが、そのアイデアも好きではありません。標準に準拠した方法でその正味の効果を得る方法はありますか?

4

3 に答える 3

2

boostにこれの特性があったことを覚えているように見えましたが、簡単に検索しても見つかりません。あなたが私と同じくらい成功しているなら、あなたはそれを自分で構築することができます.

template <typename T1, typename T2>
struct least_common_promotion;

template <>
struct least_common_promotion<short, int>
{
    typedef int type;
};

ただし、かなりの数の明示的な特殊化を指定する必要があります。boostの型特性ライブラリは、おそらくそれらの数を減らすのに役立ちます。

編集:私はばかげているように感じます。そのようなものは操作(結果の型がオペランドの型に依存する場合)には必要ですが、述語(結果の型が である場合)には必要ありませんbool。あなたは簡単に書くことができます:

template <class T1, T2>
struct unhomogenous_less : public std::binary_function<T1, T2, bool>
{
   bool operator()(T1 const& l, T2 const& r) const
   { return l < r; }
};

...

typedef typename std::iterator_traits<In>::value_type value_type_1;
typedef typename std::iterator_traits<In2>::value_type value_type_2;
other_func(first, last, first2, unhomogenous_less<value_type_1, value_type_2>());
于 2009-08-29T07:57:21.010 に答える
0

SGI の の古い実装をstd::equal例にとると、STL アルゴリズムは、同じアルゴリズムの 2 つのバージョンを持つことによって、この種の状況を処理します<。ユーザーは好みのタイプを使用できます。

template <class _InputIter1, class _InputIter2>
inline bool equal(_InputIter1 __first1, _InputIter1 __last1,
                  _InputIter2 __first2) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
                 _EqualityComparable);
  __STL_REQUIRES(typename iterator_traits<_InputIter2>::value_type,
                 _EqualityComparable);
  for ( ; __first1 != __last1; ++__first1, ++__first2)
    if (*__first1 != *__first2)
      return false;
  return true;
}

template <class _InputIter1, class _InputIter2, class _BinaryPredicate>
inline bool equal(_InputIter1 __first1, _InputIter1 __last1,
                  _InputIter2 __first2, _BinaryPredicate __binary_pred) {
  __STL_REQUIRES(_InputIter1, _InputIterator);
  __STL_REQUIRES(_InputIter2, _InputIterator);
  for ( ; __first1 != __last1; ++__first1, ++__first2)
    if (!__binary_pred(*__first1, *__first2))
      return false;
  return true;
}

(注: 古い SGI STL コードはhereから取得しました。)

于 2009-08-29T06:19:38.197 に答える