[英]Resolving overloading ambiguity with multiple inheritance of base class templates in C++
假设我正在尝试创建一个从给定基类派生的Combine
class。
template<typename ...Bases>
class Combine : public Bases... {};
这很好用。 例如,如果我有 class Foo
和 class Bar
那么 class Combine<Foo, Bar>
将实现Foo
和Bar
的所有方法。 至少我是这么认为的,直到我尝试了这个:
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
struct ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
return container[index];
}
};
struct MutableGetter : public virtual ContainerProvider {
int &get(int index) {
return container[index];
}
};
template<typename ...Bases>
class Combine : public Bases... {};
int main() {
Combine<ConstGetter, MutableGetter> container;
container.get(1); // Member 'get' found in multiple base classes of different types
}
在正常情况下,我只会使用using Super::method;
,但在这里我不知道派生方法的名称。 在一个完美的世界里,我可以使用这样的东西:
template<typename ...Bases>
class Combine : public Bases... {
using Bases::* ...;
};
但是 C++ 不允许这样做。
是否可以以某种方式实现我的Combine
class ? 我很确定编译器可以获得所有信息来解决这个边缘情况,但我不知道如何提供它来使其工作。
奇怪的问题,因为 get() 仅在一个 class 中定义可以完美地工作,但在两个? 错误? 我很好奇是否可能存在核心语言缺陷,因为编译器似乎可以解决这个问题,但我没有看到任何问题( http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects. html )。
理想的解决方案可能是MutableGetter
从ConstGetter
继承,因为从逻辑上讲,允许突变的 getter 也应该允许获取非可变版本。
struct MutableGetter : public ConstGetter {
using ConstGetter::get;
int &get(int index) {
return container[index];
}
};
这是我能得到的最接近的:
#include <iostream>
#include <vector>
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
struct ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
std::cout << "CONST" << std::endl;
return container[index];
}
};
struct MutableGetter : public virtual ContainerProvider {
int &get(int index) {
std::cout << "NON-CONST" << std::endl;
return container[index];
}
};
template <typename... Bases>
class Combine;
template <typename B1, typename B2, typename... Bases>
struct Combine<B1, B2, Bases...> : public B1, public Combine<B2, Bases...> {
using B1::get;
using Combine<B2, Bases...>::get;
};
template<typename B>
struct Combine<B> : B {
using B::get;
};
int main() {
Combine<ConstGetter, MutableGetter> container;
std::cout << container.get(0) << std::endl; // non-const
const auto &const_container = container;
std::cout << const_container.get(0) << std::endl; // const
}
不过, Combine
必须知道它的父级公开了哪些成员函数,这真的很糟糕。 如果您愿意放弃成员函数的想法并偶尔进行演员表,我找到了一个部分解决方案......:使用朋友函数
#include <iostream>
#include <vector>
struct ContainerProvider {
std::vector<int> container{1, 2, 3};
};
class ConstGetter : public virtual ContainerProvider {
[[nodiscard]] const int &get(int index) const {
std::cout << "CONST" << std::endl;
return container[index];
}
friend [[nodiscard]] const int& get(const ConstGetter &self, int i) { return self.get(i); }
};
class MutableGetter : public virtual ContainerProvider {
int &get(int index) {
std::cout << "NON-CONST" << std::endl;
return container[index];
}
friend [[nodiscard]] const int &get(MutableGetter &self, int i) {
return self.get(i);
}
};
template <typename... Bases>
class Combine : public Bases... {};
int main() {
Combine<ConstGetter, MutableGetter> container;
std::cout << get((MutableGetter&)container, 0) << std::endl;
const auto &const_container = container;
std::cout << get(const_container, 0) << std::endl;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.