微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

与 std::any 一起使用的 CRTP 与虚函数

如何解决与 std::any 一起使用的 CRTP 与虚函数

我正在尝试创建一个编译时多态设计,它不需要具有所有缺点的虚函数。但是,我正在努力创建简单、有效且易于理解的容器,该容器可以模拟将派生类保存在其基类容器中的能力。我之前对编译时可变参数向量的尝试是有效的,但代码非常混乱。这个解决方案对我来说似乎更清洁。我有实现基本 CTRP 的简单代码。但是,我创建了一个存储 std::any 对象的运行时容器,然后根据对象的类型,我可以定义应该采取的操作。我有几个问题。

  1. 与使用虚函数相比,使用 std::any 和后续的 any_cast<>()性能有何影响?

  2. 在这种情况下,std::any用法是否有效?

  3. 有没有更好的方法来实现这样的容器?

  4. 有没有办法像虚拟函数一样强制实现(通过使用 virtual <type> foo() = 0)?

  5. 创建一个将作为 CRTP 处理程序的对象是个好主意吗?所以我不会有一个用于 CRTP 调用函数,而是一个可以管理这些调用的对象?

谢谢。

这是基类:

class base {
private:
  base() = default;
  friend T;

  T& implementation = static_cast<T&>(*this);
public:
  auto do_stuff() {
    return implementation.do_stuff();
  }
};

这是实现:

#include <iostream>

class implementation_a : public base<implementation_a> {
public:
  auto do_stuff() {
    std::cout << 42 << std::endl;
  }
};

class implementation_b : public base<implementation_b> {
public:
  auto do_stuff() {
    return 420;
  }
};

这是容器:

#include <vector>
#include <any>

class crtp_vector {
private:
  std::vector<std::any> vec;

public:
  auto begin() {
    return vec.begin();
  }

  auto end() {
    return vec.end();
  }

  auto empty() {
    return vec.empty();
  }

  auto size() {
    return vec.size();
  }

  void clear() {
    vec.clear();
  }

  void push_back(const std::any& val) {
    vec.push_back(val);
  }

  auto emplace_back(const std::any& val) {
    vec.emplace_back(val);
  }
};

主要内容如下:

#include "crtp_container.h"

#include <utility>

/* crtp call handler */
template <typename T>
auto crtp_call(T& val) {
  return val.do_stuff();
}

int main() {
  crtp_vector vec;
  implementation_a A;
  implementation_b B;

  vec.push_back(A);
  vec.push_back(B);

  for(auto &member : vec) {
    if(member.type().name() == typeid(implementation_a).name()) {
      crtp_call(std::any_cast<implementation_a&>(member));
    }
    else if(member.type().name() == typeid(implementation_b).name()) {
      std::cout << crtp_call(std::any_cast<implementation_b&>(member)) << std::endl;
    }
    else {
      std::cerr << "no viable type conversion" << std::endl;
    }
  } 

  return 0;
}

解决方法

你说得太复杂了。显示的代码没有以任何方式使用 base;如果您只是将其完全删除,则不会有任何改变。即使你一直说“CRTP”,你实际上并没有依赖 CRTP 做任何事情。

代码没有使用 std::any 的能力来保存任何类型;它仅用于保存编译时已知的一组固定类型之一。 std::variant 更适合这个。

总而言之,这个例子可以归结为:

class implementation_a {
public:
  auto do_stuff() {
    std::cout << 42 << std::endl;
  }
};

class implementation_b {
public:
  auto do_stuff() {
    std::cout << 420 << std::endl;
    return 420;
  }
};

int main() {
  implementation_a A;
  implementation_b B;

  std::vector<std::variant<implementation_a,implementation_b>> vec;
  vec.push_back(A);
  vec.push_back(B);

  for(auto &member : vec) {
      std::visit([](auto& elem) { elem.do_stuff(); },member);
  } 

  return 0;
}

Demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。