具有多重继承的C++转换运算符



考虑使用混合模式的多重(实现(继承的情况:

#include <string>
#include <iostream>
template <typename... Bases>
struct Overloads : public Bases... {};
struct Human {};
struct Animal {};
struct Named {
std::string name_;
void setName(const std::string& name) {
name_ = name;  
}
const std::string& getName() const noexcept { return name_; }
};
template <typename OverloadsType>
struct Actor : public OverloadsType {
Actor() : OverloadsType() {}
template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) {
// ???????
this->setName(other_actor.getName());
}
};
int main() {
Actor<Overloads<Human, Named>> named_human;
named_human.setName("Bob");
std::cout << named_human.getName() << 'n';
Actor<Overloads<Animal, Named>> named_animal;
Actor<Overloads<Animal, Named>> animal_once_a_human (named_human);
std::cout << animal_once_a_human.getName() << 'n';    
}

代码工作正常,打印两个Bob:链接

我想要两样东西

  1. 即使OverloadsTypeOtherOverloads不是从Named派生的,也要编译转换运算符(this->setName(other_actor.getName());应该被忽略或根本不编译(

  2. 泛化"转移";来自(通用(基类的信息,而不仅仅是名称

我该怎么做?

这是一个基本的蓝图。这可以进一步细化,以便概念实际上检查getName()是否返回std::string

#include <string>
#include <iostream>
template<typename T>
concept has_a_name = requires(T &t) {
{ t.getName() };
};
template<typename T, typename U>
void give_name(const T &t, U &u)
{
}
template<has_a_name T, typename U>
void give_name(const T &t, U &u)
{
u.setName(t.getName());
}

struct tom {
std::string getName() const
{
return "Tom";
}
};
struct jerry {};
struct cartoon {
void setName(const std::string &s)
{
std::cout << s << "n";
}
template<typename T>
cartoon(const T &t)
{
give_name(t, *this);
}
};
int main()
{
tom Tom;
jerry Jerry;
cartoon mgm{Tom}, mgm2{Jerry};
return 0;
}

就概括而言,任何可能的";通用的";定义getter和setter的方法要么比这更长,要么使用晦涩、晦涩、难以阅读的模板,最终表达非常简单的操作。

一个简单的概念定义了实现特定getter的每个类,以及一对模板函数,通过简单的重载解析来选择存根或真正的交易,这很容易阅读、理解和遵循。

我想要两样东西

  1. 即使OverloadsType和OtherOverloads不是从Named派生的,也要编译转换运算符(this->setName(other_actor.getName(((;应忽略或根本不编译(

  2. 泛化"转移";来自(通用(基类的信息,而不仅仅是名称

我该怎么做?

因此,如果源也有基类,则应该复制它,否则我们应该使用默认构造的实例。这很简单。

我们可以定义一个函数来提取初始值设定项,如果有,则是基的副本,否则是默认构造的实例:

template <std::semiregular T, typename U>
constexpr auto extract(const U& u) -> T {
if constexpr (std::derived_from<U, T>) {
return u;
}
else {
return T();
}
}

然后我们可以使用它来初始化";过载":

template <typename... Bases>
struct Overloads : public Bases... {
Overloads() = default;
template <typename OtherOverloads>
Overloads(const OtherOverloads& other_overloads) : Bases{extract<Bases>(other_overloads)}... {}
};

然后我们可以使用该逻辑来初始化actor:

template <typename OtherOverloads>
Actor(const Actor<OtherOverloads>& other_actor) : OverloadsType(other_actor) {}

请参阅https://godbolt.org/z/ofjPb8x75

最新更新