3

基本的に、C ++ 11テンプレートを使用して、テンプレート化された関数がイテレーターの間接レベルを検出し、それに応じて関数を異なる方法でコンパイルできるようにすることができるかどうかを知りたいです。たとえば、コンパイルされないコードは次のとおりです。

#include <vector>
#include <list>
#include <type_traits>
#include <iostream>

struct MyStruct
{
  int value;
  MyStruct(int value = 42) : value(value) { }
  const int& getInt() const { return value; }
};

typedef std::list<MyStruct> StructList;
typedef std::vector<const MyStruct*> StructPtrVector;

template <typename ITER_TYPE>
const int& getIteratorInt(ITER_TYPE iter)
{
  if (std::is_pointer<decltype(*iter)>::value)
    return (*iter)->getInt(); // Won't compile -> MyStruct has no operator-> defined
  return iter->getInt(); // Won't compile -> MyStruct* has the wrong level of indirection
}

template <typename LIST_TYPE>
void PrintInts(const LIST_TYPE& intList)
{
  for (auto iter = intList.begin(); iter != intList.end(); ++iter)
    std::cout << getIteratorInt(iter) << std::endl;
}

int main(void)
{
  StructList structList;
  StructPtrVector structPtrs;
  int values[5] = { 1, 4, 6, 4, 1 };
  for (unsigned i = 0; i < 5; ++i)
  {
    structList.push_back(values[i]);
    structPtrs.push_back(&structList.back());
  }
  PrintInts(structList);
  PrintInts(structPtrs);

  return 0;
}

明らかな状況は、オブジェクトのリストがあり、次にオブジェクトへのポインターの別の種類のリストがある場合です。そして、あなたがしたいことは、両方をオブジェクトのリストとして扱うことにより、両方のリストで同じです。

上記のコードは、コンパイル時に実行する必要のある論理チェックを実行しているため、コンパイルされません。プリプロセッサマクロでこれを行う方法があるかどうかはわかりません。単純なものを試しました#if std::is_pointer<decltype(*iter)>::value == trueが、コンパイラは常にそれをfalseと見なしているようです。(私はこれまでプリプロセッサマクロを試したことがありませんが、それは明らかに適切な方法ではありません。)

それが可能であるかどうか何か考えはありますか?

4

1 に答える 1

7

、などのメタ関数に応じて2つの実装から選択する場合は、SFINAEの原理に基づいて機能is_pointerするを使用します。std::enable_if

template <typename ITER_TYPE>
auto getIteratorInt(ITER_TYPE iter) ->
typename std::enable_if< std::is_pointer< 
        typename std::iterator_traits< ITER_TYPE >::value_type >::value,
    const int& >::type
{
  return (*iter)->getInt();
}

template <typename ITER_TYPE>
auto getIteratorInt(ITER_TYPE iter) ->
typename std::enable_if< ! std::is_pointer< 
        typename std::iterator_traits< ITER_TYPE >::value_type >::value,
    const int& >::type
{
  return iter->getInt();
}

このように、テンプレートのインスタンス化では、指定されたテンプレート引数に対して有効なコード行のみが表示されます。

この修正をコードに機械的に適用しました…複数の間接参照の使用を推奨したり、修正された実装が堅牢であることを示唆したりしていません。

于 2012-04-10T07:56:36.727 に答える