質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.50%

テンプレートクラスから他のテンプレートクラスを使用する際にエラーになってしまう

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 338

score 6

C++の初学者です。
Visual Studio 2017を使用しております。
以下のコードで、std:arrayもどきを作成しならが、クラステンプレートを勉強しております。

arrayクラスにより、
任意型の要素を持つ配列を作成すること
指定した要素番号の値を取得すること
配列のサイズ=要素数を取得すること
は可能になりました。

array_iteratorクラスにより、イテレータcに対して*cにより値を取得することも可能になりました。

#include <iostream>

template < typename T, std::size_t N >
struct array
{
    using value_type = T;
    using reference = T & ;
    using size_type = std::size_t;
//    using iterator = array_iterator<array>;

    value_type storage[N]; //大きさN、型Tのメンバー変数arrayを作る
    size_type size() { return N; } //arrayの大きさNを返すメンバー関数
    reference operator [] (size_type i) { return storage[i]; } //i番目の要素を返す

    // 先頭要素のイテレーター
    int begin() { return array_iterator(*this , 0); } 
};

template < typename Array >
struct array_iterator
{
    Array & a;
    std::size_t i;

//    array_iterator() : a(a), i(i) {}; //デフォルトコンストラクター
    array_iterator(Array & x, std::size_t j)
        : a(x), i(j) { } //コンストラクターでデータメンバーを初期化 a=x,i=jを行っている?

    // いま参照している要素へのリファレンスを返す
//    array::reference operator *()
    double & operator *() //任意の型に対応する為、Array & operator *()にしたいが、エラーになる。
    {
        return a[i];
    }
};

auto print = [](auto &x) { std::cout << x << "\n"; };

int main()
{
    array<int, 5> a = { 1,2,3,4,5 };
    print(a[3]);      // 4
    a.size();  // 5 print(a.size());はエラーになる(std::size_tをintに変換できない?)
//    a.begin(); // イテレータ0 
//    *(a.begin()) // 最初の要素の値 1

    array<double, 5> b = { 1.,2.,3.,4.,5. };
    print(b[3]);      // 4.
    b.size();  // 5 print(b.size());はエラーになる(std::size_tをintに変換できない?)
//    b.begin(); // イテレータ0
//    *(b.begin()) // 最初の要素の値 1.

    array_iterator<array<double,5> > c(b,1);
    print(*c);        // bの要素1の値 2.
}


次に、arrayクラスのメンバー関数beginにより、先頭要素のイテレータをarray_iteratorにより作成し、それを返したいのですが、エラーとなってしまいます。44,50行目をコメントアウトすると、

a.begin();
b.begin();


コンパイルエラーとなってしまいます。
エラーメッセージは
”Severity    Code    Description    Project    File    Line    Suppression State
Error    C2955    'array_iterator': use of class template requires template argument list"    
です。

int begin() { return array_iterator(*this , 0); }

修正方法を教えていただければと思います。
よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

僕ならこうする:

#include <iostream>

template < typename T, std::size_t N >
struct array {
    using value_type = T;
    using reference = T&;
    using const_reference = const T&;
    using size_type = std::size_t;
    using iterator = value_type*;
    using const_iterator = const value_type*;

    //    using iterator = array_iterator<array>;

    value_type storage[N]; //大きさN、型Tのメンバー変数arrayを作る
    size_type size() const { return N; } //arrayの大きさNを返すメンバー関数
    reference operator [] (size_type i) { return storage[i]; } //i番目の要素を返す
    const_reference operator [] (size_type i) const { return storage[i]; } //i番目の要素を返す

    // 先頭要素のイテレーター
    const value_type* begin() const { return storage; }
    value_type* begin() { return storage; }
    const value_type* end() const { return storage+N; }
    value_type* end() { return storage+N; }
};

template<typename T>
void print(const T& x) { std::cout << x << "\n"; }

#include <algorithm>

int main() {
    array<int, 5> a = { 1,2,3,4,5 };
    print(a[3]);
    print(a.size());
    std::for_each(a.begin(), a.end(), print<int>);

    array<double, 5> b = { 1.,2.,3.,4.,5. };
    print(b[3]);
    print(b.size());
    std::for_each(b.begin(), b.end(), print<double>);

    array<double, 5>::iterator c = b.begin()+1;
    print(*c);        // bの要素1の値 2.
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/06/20 00:25

    いやだから、"先頭要素のイテレーター" を返すべきなのに ”先頭要素” を返してるじゃない。
    イテレータを返すなら print(*a.begin()); じゃないと変だし。

    キャンセル

  • 2021/06/20 13:29

    > array_iteratorで実装する場合についても、教えていただけるとありがいたです。

    回答しました。

    キャンセル

  • 2021/06/20 14:06

    「"先頭要素のイテレーター" を返すべきなのに ”先頭要素” を返してるじゃない。」
    確かに、std::arrayのbegin()ならイテレータを返さないといけませんね。

    キャンセル

check解決した方法

0

関数、クラスの定義順を、依存関係的に他に依存しないものの順に、
print
array_iterator
array
main
にする必要があるんですね。

また、エラーメッセージにあるように、
int begin() { return array_iterator(*this , 0); } 
のところは、
iterator begin() { return array_iterator<array>(*this, 0); }
のように、array_iteratorのテンプレート引数<array>を指定することで解決できました。

#include <iostream>

template<typename T>
void print(const T &x) { std::cout << x << "\n"; }

template < typename Array >
struct array_iterator
{
    Array & a;
    std::size_t i;

    array_iterator(Array & x, std::size_t j)
        : a(x), i(j) //コンストラクターでデータメンバーを初期化 a=x,i=jを行っている 
    {
        print(a[3]);      // 初期化のチェック 4
    }

    // いま参照している要素へのリファレンスを返す
    typename Array::reference operator *() { return a[i]; }
};

template < typename T, std::size_t N >
struct array
{
    using value_type = T;
    using reference = T & ;
    using size_type = std::size_t;
    using iterator = array_iterator<array<T,N>>;

    value_type storage[N]; //大きさN、型Tのメンバー変数arrayを作る
    size_type size() { return N; } //arrayの大きさNを返すメンバー関数
    reference operator [] (size_type i) { return storage[i]; } //i番目の要素を返す

    // 先頭要素のイテレーター
    iterator begin() { return array_iterator<array>(*this, 0); }
};

int main()
{
    array<int, 5> a = { 100,2,3,4,5 };
    print(a[3]);      // 4
    print(a.size());  // 5
    auto iter1=a.begin(); // array_iterator(a,0)
    print(*iter1);     //100

    array<double, 5> b = { 200.,2.,3.,4.,5. };
    print(b[3]);      // 4.
    print(b.size());  // 5.
    auto iter2 = b.begin(); // array_iterator(b,0)
    print(*iter2);     //200.

    array_iterator<array<double,5> > c(b,1);
    print(*c);        // bの要素1の値 2.
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

かなりテキトーな実装やけど:

#include <iostream>

template<typename Array>
struct array_iterator {
  using value_type = Array::value_type;
  array_iterator(value_type* p) : ptr(p) {}
  value_type& operator*() { return *ptr; }
  array_iterator& operator++() { ++ptr; return *this; }
  array_iterator  operator++(int) { array_iterator t(ptr); ++ptr; return t; }
  array_iterator& operator--() { --ptr; return *this; }
  array_iterator  operator--(int) { array_iterator t(ptr); --ptr; return t; }
  bool operator==(array_iterator rhs) const { return ptr == rhs.ptr; }
  bool operator!=(array_iterator rhs) const { return ptr != rhs.ptr; }
  value_type* ptr;
};

template < typename T, std::size_t N >
struct array {
    using value_type = T;
    using reference = T&;
    using const_reference = const T&;
    using size_type = std::size_t;
    using iterator = array_iterator<array<T,N>>;

    //    using iterator = array_iterator<array>;

    value_type storage[N]; //大きさN、型Tのメンバー変数arrayを作る
    size_type size() const { return N; } //arrayの大きさNを返すメンバー関数
    reference operator [] (size_type i) { return storage[i]; } //i番目の要素を返す
    const_reference operator [] (size_type i) const { return storage[i]; } //i番目の要素を返す

    iterator begin() { return iterator(storage); }
    iterator end()   { return iterator(storage+N); }
};

template<typename T>
void print(const T& x) { std::cout << x << "\n"; }

#include <algorithm>

int main() {
    array<int, 5> a = { 1,2,3,4,5 };
    print(a[3]);
    print(a.size());
    std::for_each(a.begin(), a.end(), print<int>);

    array<double, 5> b = { 1.,2.,3.,4.,5. };
    print(b[3]);
    print(b.size());
    std::for_each(b.begin(), b.end(), print<double>);

    array<double, 5>::iterator c = b.begin();
    print(*++c);        // bの要素1の値 2.
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/06/20 14:05

    回答ありがとうございます。
    ただ、私の環境ではコンパイルエラーがたくさん出てしまいました。

    キャンセル

  • 2021/06/20 15:11 編集

    あらま、コンパイラの癖ってやつか。僕のは VC++ 2019 v16.10.2(最新)

    たとえば
    using value_type = Array::value_type;
    コレは
    using value_type = typename Array::value_type;
    が正解かも。

    キャンセル

  • 2021/06/20 15:29

    using value_type = typename Array::value_type;
    にしてもエラーです。
    もしかして、arrayクラスのvalue_typeという意味で、以下のようにする意図でしょうか? ただ、これでもエラーにはなるんですが。
    using value_type = typename array::value_type;

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • C++に関する質問
  • テンプレートクラスから他のテンプレートクラスを使用する際にエラーになってしまう