3

私はこのコードを持っています:

template<typename T>
class Listoid{

  private:
    std::vector<T> list;

  public:
    typedef typename std::vector<T>::iterator iterator;

    iterator begin() {return list.begin();}
    iterator end() {return list.end();}

  public:
    Listoid(T t) {
      list.push_back(t);
    }

  const T operator [](int i){
    return list[i];
  }

  void addElem(T ne){
    list.push_back(ne);
  }

  friend T cons(T new_elem, Listoid<T> list);

};

template<typename T>
Listoid<T> cons(T new_elem, Listoid<T> list){

  Listoid<T> new_list(new_elem);
  for(typename Listoid<T>::iterator it = list.begin(), e = list.end();
        it != e; ++it){
          new_list.addElem(*it);
        }
  return new_list;
}


int main(){

  Listoid<int> lista(312);
  lista.addElem(22);

  Listoid<int> lista2 = cons(21, lista);

  return EXIT_SUCCESS;
}

しかし、私はそれをコンパイルできません。次のエラーが表示されます。

/tmp/listoid-3kYCmd.o: In function `main':
listoid.cpp:(.text+0xda): undefined reference to `cons(int, Listoid<int>)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

多分それは本当に簡単ですが、私はそれを解決することはできません. 誰か助けてくれませんか?

4

4 に答える 4

5

cons関数テンプレートが単純な関数ではないことをコンパイラに伝える必要があります。次の構文を使用します。

friend T cons <>(T new_elem, Listoid<T> list);

関数名の後に<>を付けてください。

それ以外の場合は、関数テンプレートではなく、単純な関数を検索しています。それはリンカーが教えてくれます。

[アップデート]

また、フレンド クラスの前に関数の前方宣言を追加することを忘れないでください。これにより、クラスはフレンドが何であるかを知ることができます。

template<typename T>
Listoid<T> cons(T new_elem, Listoid<T> list);

[更新2]

関数テンプレートの型を変更し、クラスの前方宣言を追加します。見る:

template<typename T>
class Listoid;
template<typename T>
Listoid<T> cons(T new_elem, Listoid<T> list);

template<typename T>
class Listoid{
...

  friend Listoid<T> cons <>(T new_elem, Listoid<T> list);

};

それは私のために働く:ideone

于 2012-09-17T20:05:02.457 に答える
1

friend T cons(T new_elem, Listoid<T> list);はテンプレートではありません。後で関数template<typename T> Listoid<T> cons(T new_elem, Listoid<T> list)のオーバーロードが異なりcons()ます。FAQを参照してください。

于 2012-09-17T20:06:11.013 に答える
1

テンプレート宣言と正しい戻り値の型で関数宣言を再処理してみてください:

   template<typename U> friend Listoid<U> cons(U new_elem, Listoid<U> list);

そして、名前を変更typenameして、クラス テンプレートのテンプレート タイプをシャドウしないようにします。

于 2012-09-17T20:10:19.893 に答える
1

問題は、 の 2 つの異なる宣言があることですcons。1 つはfriend宣言内にあり、もう 1 つは名前空間レベルの外にあります。テンプレートの友情は、最初に見えるほど簡単ではありません。さまざまなオプションの長い説明とともに、この他の回答を読むことをお勧めします. 特に、テンプレートの特定の特殊化のみをフレンドリにしたい場合 (どうやら)、クラス テンプレートの前に、事前に宣言を提供する必要があります。

template<typename T>
class Listoid;
template<typename T>
T cons(T new_elem, Listoid<T> list);
template<typename T>
class Listoid{
   friend T cons<T>(T,Listoid<T>);
...

現在のフォームでは、非テンプレート関数をフレンドとして宣言しています。その非テンプレート関数はテンプレートよりも適切に一致し (型が一致する場合、非テンプレートはテンプレートよりも優先されます)、コンパイラは非テンプレート関数への依存関係を生成します。

int const(int,Listoid<int>);
于 2012-09-17T20:20:55.717 に答える