从泛型基础多次继承时调用不明确 class
Ambiguous call when inheriting multiple times from generic base class
我想克隆一个包含多种类型的 std::list
的数据结构,同时移动一些迭代器以指向新的 std::list
的元素。为此,我创建了一个通用类型 Translate<T>
表示从旧列表中的 std::list<T>::iterator
到新列表中的映射。然后我有一个新的 class 从 Translate<T>
继承我的数据结构的所有需要的类型 T
。
这是一个简化的示例(仅使用恒等函数):
#include <list>
struct T1 {};
struct T2 {};
template<typename T>
class Translate {
public:
typename std::list<T>::iterator operator()(typename std::list<T>::iterator x) {
return x; // more complex in the real world, but doesn't matter here
}
};
int main() {
std::list<T1> l1{};
std::list<T2> l2{};
class : public Translate<T1>, public Translate<T2> {} tr;
tr(l1.begin());
}
这给了我以下编译器错误:
mwe.cpp: In function ‘int main()’:
mwe.cpp:19:15: error: request for member ‘operator()’ is ambiguous
tr(l1.begin());
^
mwe.cpp:9:34: note: candidates are: ‘typename std::__cxx11::list<T>::iterator Translate<T>::operator()(typename std::__cxx11::list<T>::iterator) [with T = T2; typename std::__cxx11::list<T>::iterator = std::_List_iterator<T2>]’
typename std::list<T>::iterator operator()(typename std::list<T>::iterator x) {
^~~~~~~~
mwe.cpp:9:34: note: ‘typename std::__cxx11::list<T>::iterator Translate<T>::operator()(typename std::__cxx11::list<T>::iterator) [with T = T1; typename std::__cxx11::list<T>::iterator = std::_List_iterator<T1>]’
调用有什么歧义? std::list<T>::iterator
不能相互转换。
它有效 如果我手动将每个 T
的实现复制到子 class 中,但这正是使用时试图避免的泛型和继承。
此代码为ill-formed。如果 operator()
在派生的 class 中不可用,则名称查找仅考虑基数 class 如果有 恰好 一个基数 class.如果有多个基数 class,则基数 class 的 none 将被视为名称查找。
正如您所提到的,您可以将 operator()
的实现复制到派生的 class 中,这很有效,但您也可以将两个 operator()
名称都带入带有 using
指令的派生 class,如下所示:
class : public Translate<T1>, public Translate<T2> {
public:
using Translate<T1>::operator();
using Translate<T2>::operator();
} tr;
这里是 demo。
我想克隆一个包含多种类型的 std::list
的数据结构,同时移动一些迭代器以指向新的 std::list
的元素。为此,我创建了一个通用类型 Translate<T>
表示从旧列表中的 std::list<T>::iterator
到新列表中的映射。然后我有一个新的 class 从 Translate<T>
继承我的数据结构的所有需要的类型 T
。
这是一个简化的示例(仅使用恒等函数):
#include <list>
struct T1 {};
struct T2 {};
template<typename T>
class Translate {
public:
typename std::list<T>::iterator operator()(typename std::list<T>::iterator x) {
return x; // more complex in the real world, but doesn't matter here
}
};
int main() {
std::list<T1> l1{};
std::list<T2> l2{};
class : public Translate<T1>, public Translate<T2> {} tr;
tr(l1.begin());
}
这给了我以下编译器错误:
mwe.cpp: In function ‘int main()’:
mwe.cpp:19:15: error: request for member ‘operator()’ is ambiguous
tr(l1.begin());
^
mwe.cpp:9:34: note: candidates are: ‘typename std::__cxx11::list<T>::iterator Translate<T>::operator()(typename std::__cxx11::list<T>::iterator) [with T = T2; typename std::__cxx11::list<T>::iterator = std::_List_iterator<T2>]’
typename std::list<T>::iterator operator()(typename std::list<T>::iterator x) {
^~~~~~~~
mwe.cpp:9:34: note: ‘typename std::__cxx11::list<T>::iterator Translate<T>::operator()(typename std::__cxx11::list<T>::iterator) [with T = T1; typename std::__cxx11::list<T>::iterator = std::_List_iterator<T1>]’
调用有什么歧义? std::list<T>::iterator
不能相互转换。
它有效 如果我手动将每个 T
的实现复制到子 class 中,但这正是使用时试图避免的泛型和继承。
此代码为ill-formed。如果 operator()
在派生的 class 中不可用,则名称查找仅考虑基数 class 如果有 恰好 一个基数 class.如果有多个基数 class,则基数 class 的 none 将被视为名称查找。
正如您所提到的,您可以将 operator()
的实现复制到派生的 class 中,这很有效,但您也可以将两个 operator()
名称都带入带有 using
指令的派生 class,如下所示:
class : public Translate<T1>, public Translate<T2> {
public:
using Translate<T1>::operator();
using Translate<T2>::operator();
} tr;
这里是 demo。