2

MSVC で正常にコンパイルされるコードをいくつか入手しました (または、それを送ってくれた Windows 開発者はそう言っています) が、CLang ではエラーが発生します。周りを見回してみると、CLang はテンプレートの特殊化の解決に関して実際により厳密であることがわかりましたが、私の場合、特殊化をどこに置くべきかわかりません。基本的に、私のファイルの 1 つには次のような構造体があります。

template<>
struct iterator_traits< char * >   // error is here
{
    typedef random_access_iterator_tag iterator_category;
    typedef char value_type;
    typedef ptrdiff_t difference_type;
    typedef difference_type distance_type;
    typedef char * pointer;
    typedef char & reference;
};

これはnamespace stdブロック内です。エラーメッセージは次のとおりです。

Explicit specialization of 'std::iterator_traits<char *>' after instantiation

同じエラー メッセージの別の部分 (Xcode でエラー メッセージを「展開」して表示) には と表示されImplicit instantiation first required here、それをクリックするとstl_iterator.h、具体的には次の行 (642 行目) に移動します。

typedef typename iterator_traits<_Iterator>::iterator_category
                                                         iterator_category;

この場合、何をするのが正しいのか誰か知っていますか?クラスに関する例は見たことがありますが、構造体に関する例は見たことがありません。

4

1 に答える 1

8

コンパイラは、ジェネリックテンプレートをインスタンス化した後、テンプレートを特殊化しようとしていると文句を言っています。その時点までに、コンパイラはすでにジェネリックテンプレートをインスタンス化に使用しており、代わりにスペシャライゼーションを使用することはできません。 。言い換えれば、このようなもの:

template <typename T>
struct X
{
    // Generic implementation
};

// Instantiate template by using it in any way
X<int> foo;

template<>
struct X<int>
{
    // Specialization implementation for int
};

修正は、インスタンス化される前に特殊化を定義することです。したがって、この例では、X<int>特殊化を使用される場所の前に移動しますX<int>

STLはすでにstd::iterator_traitポインタ型の特殊化を定義しているため、ここで独自の特殊化を定義する必要はありませんchar*。通常、これは、ポインターではないユーザー定義のイテレーター型に対してのみ行います。C++03標準の§24.3.1/2を参照してください。

[テンプレートiterator_traits<Iterator>]は次のようなポインタに特化しています

template<class T> struct iterator_traits<T*> {
  typedef ptrdiff_t difference_type;
  typedef T value_type;
  typedef T* pointer;
  typedef T& reference;
  typedef random_access_iterator_tag iterator_category;
};

constおよびとしてのポインタ

template<class T> struct iterator_traits<const T*> {
  typedef ptrdiff_t difference_type;
  typedef T value_type;
  typedef const T* pointer;
  typedef const T& reference;
  typedef random_access_iterator_tag iterator_category;
};

したがって、独自のstd::iterator_traits<char*>専門分野を提供する意味はありません。char*はユーザー定義型ではないため、標準による未定義動作でもあります。§17.4.3.1/1は言う:

std特に指定がない限り、C++プログラムが名前空間stdまたは名前空間内の名前空間に宣言または定義を追加することは定義されていません。プログラムは、任意の標準ライブラリテンプレートのテンプレート特殊化を名前空間に追加できますstd。標準ライブラリテンプレートのこのような特殊化(完全または部分的)は、宣言が外部リンケージのユーザー定義名に依存しない限り、また特殊化が元のテンプレートの標準ライブラリ要件を満たさない限り、未定義の動作になります。163)

163)他のライブラリテンプレートをインスタンス化するライブラリコードは、標準の最小要件を満たすユーザー提供のスペシャライゼーションで適切に機能するように準備する必要があります

于 2012-10-04T16:59:20.710 に答える