[英]C++: Templated code compiles and runs fine with clang++, but fails with g++
Take a look at this implementation of a linked list: 看一下链表的此实现:
#include <memory>
#include <type_traits>
#include <iostream>
using namespace std;
template<typename D>
class List {
struct Node {
shared_ptr<D> data;
Node* next;
Node(shared_ptr<D> d, Node* p, Node* n) : data(d), next(n) {}
~Node() {
data.reset();
delete next;
}
};
template <bool isconst = false>
struct iterator : public std::iterator<std::forward_iterator_tag, shared_ptr<D>> {
typedef std::forward_iterator_tag iterator_category;
typedef shared_ptr<D> value_type;
typedef std::ptrdiff_t Distance;
typedef typename conditional<isconst, const value_type&, value_type&>::type
Reference;
typedef typename conditional<isconst, const value_type*, value_type*>::type
Pointer;
typedef typename conditional<isconst, const Node*, Node*>::type
nodeptr;
iterator(nodeptr x = nullptr) : curr_node(x) {}
iterator(const iterator<false>& i) : curr_node(i.curr_node) {}
Reference operator*() const { return curr_node->data; }
Pointer operator->() const { return &(curr_node->data); }
template<bool A>
friend bool operator==(const iterator<A>& a, const iterator<A>& b) {
return a.curr_node == b.curr_node;
}
template<bool A>
friend bool operator!=(const iterator<A>& a, const iterator<A>& b) {
return !(a.curr_node == b.curr_node);
}
friend class List<D>;
iterator& operator++() {
curr_node = curr_node->next;
return *this;
}
private:
nodeptr curr_node;
};
public:
List() {
head = nullptr;
}
int len() const {
int ret = 0;
for (const auto& n : *this) {
ret++;
}
return ret;
}
~List() {
delete head;
}
std::ostream& dump(std::ostream &strm) const {
for (const auto s : *this) {
strm << *s << std::endl;
}
return strm;
}
iterator<false> begin() {
return iterator<false>(head);
}
iterator<false> end() {
return iterator<false>(nullptr);
}
iterator<true> begin() const {
return iterator<true>(head);
}
iterator<true> end() const {
return iterator<true>(nullptr);
}
private:
Node* head;
};
The part giving me problems is the iterator
implementation for this list. 给我带来问题的部分是该列表的
iterator
实现。 The iterator template is supposed to provide both mutable and const
iterators. 迭代器模板应该提供可变和
const
迭代器。
This is a program which uses this implementation: 这是一个使用此实现的程序:
#include "List.h"
#include <iostream>
int main( int argc, const char *argv[] ) {
List<int> l;
std::cout << l.len() << std::endl;
return 0;
}
The program compiles and runs fine if I use clang++
, but the compilation fails for g++
with the following error: 如果我使用
clang++
,则程序可以编译并运行良好,但是对于g++
,编译失败,并出现以下错误:
In file included from t.cpp:1:
List.h: In instantiation of ‘struct List<int>::iterator<false>’:
List.h:136:5: required from ‘int List<D>::len() const [with D = int]’
t.cpp:7:24: required from here
List.h:64:21: error: redefinition of ‘template<bool A> bool operator==(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’
friend bool operator==(const iterator<A>& a, const iterator<A>& b) {
^~~~~~~~
List.h:64:21: note: ‘template<bool A> bool operator==(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’ previously declared here
List.h:69:21: error: redefinition of ‘template<bool A> bool operator!=(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’
friend bool operator!=(const iterator<A>& a, const iterator<A>& b) {
^~~~~~~~
List.h:69:21: note: ‘template<bool A> bool operator!=(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’ previously declared here
What's the cause of this error? 此错误的原因是什么? How can I fix this?
我怎样才能解决这个问题?
The problem seems to be here: 问题似乎在这里:
template <bool isconst = false>
struct iterator : public std::iterator<std::forward_iterator_tag, shared_ptr<D>> {
template<bool A>
friend bool operator==(const iterator<A>& a, const iterator<A>& b) {
return a.curr_node == b.curr_node;
}
This is saying: For all values of isconst
(the outer template parameter), define a template function template<bool A> bool operator==
. 这就是说:对于
isconst
所有值(外部模板参数),请定义模板函数template<bool A> bool operator==
。
So instantiating iterator<true>
will define template<bool A> bool operator==
, and then instantiating iterator<false>
will define template<bool A> bool operator==
again, causing a redefinition error. 因此,实例化
iterator<true>
将定义template<bool A> bool operator==
,然后实例化iterator<false>
将再次定义template<bool A> bool operator==
,从而导致重新定义错误。
Solution: Remove the inner template. 解决方案:卸下内部模板。 Have each instantiation of
iterator
only define its own operator==
: 让
iterator
每个实例仅定义其自己的operator==
:
template <bool isconst = false>
struct iterator : public std::iterator<std::forward_iterator_tag, shared_ptr<D>> {
friend bool operator==(const iterator& a, const iterator& b) {
return a.curr_node == b.curr_node;
}
(Here iterator
automatically refers to iterator<isconst>
, ie the current instantiation.) (这里的
iterator
自动引用iterator<isconst>
,即当前实例。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.