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()函数的不同重载。请参阅常见问题解答

于 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

问题是您有两个不同的声明cons,一个在friend声明中,另一个在命名空间级别之外。模板中的友谊并不像一开始那样简单,我建议您阅读这个其他答案,并详细解释不同的选项。特别是,如果您希望(看起来)只与模板的特定专业化友好,则需要在类模板之前预先提供声明:

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 回答