首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型擦除类型擦除,`任何问题?

类型擦除类型擦除,`任何问题?
EN

Stack Overflow用户
提问于 2016-08-09 02:04:46
回答 1查看 2.8K关注 0票数 24

因此,假设我想使用类型擦除来输入erase。

我可以为变体创建伪方法,从而实现自然的:

代码语言:javascript
复制
pseudo_method print = [](auto&& self, auto&& os){ os << self; };

std::variant<A,B,C> var = // create a variant of type A B or C

(var->*print)(std::cout); // print it out without knowing what it is

我的问题是,如何将其扩展到std::any

这不可能是“原始的”。但是在我们赋值/构造std::any的时候,我们就有了我们需要的类型信息。

所以,从理论上讲,一个增强的any

代码语言:javascript
复制
template<class...OperationsToTypeErase>
struct super_any {
  std::any data;
  // or some transformation of OperationsToTypeErase?
  std::tuple<OperationsToTypeErase...> operations;
  // ?? what for ctor/assign/etc?
};

可以以某种方式自动重新绑定一些代码,以便上面类型的语法可以工作。

理想情况下,它的用法和变体的用法一样简洁。

代码语言:javascript
复制
template<class...Ops, class Op,
  // SFINAE filter that an op matches:
  std::enable_if_t< std::disjunction< std::is_same<Ops, Op>... >{}, int>* =nullptr
>
decltype(auto) operator->*( super_any<Ops...>& a, any_method<Op> ) {
  return std::get<Op>(a.operations)(a.data);
}

现在,我可以将其保留为一个类型,同时合理地使用lambda语法以保持简单吗?

理想情况下,我希望:

代码语言:javascript
复制
any_method<void(std::ostream&)> print =
  [](auto&& self, auto&& os){ os << self; };

using printable_any = make_super_any<&print>;

printable_any bob = 7; // sets up the printing data attached to the any

int main() {
  (bob->*print)(std::cout); // prints 7
  bob = 3.14159;
  (bob->*print)(std::cout); // prints 3.14159
}

或类似的语法。这不可能吗?不可行?容易吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-08-10 13:54:50

这是我的解决方案。它看起来比Yakk的短,而且不使用std::aligned_storage和placement new。它还支持状态函数式和局部函数式(这意味着可能永远不可能编写super_any<&print>,因为print可以是局部变量)。

any_method:

代码语言:javascript
复制
template<class F, class Sig> struct any_method;

template<class F, class Ret, class... Args> struct any_method<F,Ret(Args...)> {
  F f;
  template<class T>
  static Ret invoker(any_method& self, boost::any& data, Args... args) {
    return self.f(boost::any_cast<T&>(data), std::forward<Args>(args)...);
  }
  using invoker_type = Ret (any_method&, boost::any&, Args...);
};

make_any_method:

代码语言:javascript
复制
template<class Sig, class F>
any_method<std::decay_t<F>,Sig> make_any_method(F&& f) {
  return { std::forward<F>(f) };
}

super_any:

代码语言:javascript
复制
template<class...OperationsToTypeErase>
struct super_any {
  boost::any data;
  std::tuple<typename OperationsToTypeErase::invoker_type*...> operations = {};

  template<class T, class ContainedType = std::decay_t<T>>
  super_any(T&& t)
    : data(std::forward<T>(t))
    , operations((OperationsToTypeErase::template invoker<ContainedType>)...)
  {}

  template<class T, class ContainedType = std::decay_t<T>>
  super_any& operator=(T&& t) {
    data = std::forward<T>(t);
    operations = { (OperationsToTypeErase::template invoker<ContainedType>)... };
    return *this;
  }
};

运算符->*

代码语言:javascript
复制
template<class...Ops, class F, class Sig,
  // SFINAE filter that an op matches:
  std::enable_if_t< std::disjunction< std::is_same<Ops, any_method<F,Sig>>... >{}, int> = 0
>
auto operator->*( super_any<Ops...>& a, any_method<F,Sig> f) {
  auto fptr = std::get<typename any_method<F,Sig>::invoker_type*>(a.operations);
  return [fptr,f, &a](auto&&... args) mutable {
    return fptr(f, a.data, std::forward<decltype(args)>(args)...);
  };
}

用法:

代码语言:javascript
复制
#include <iostream>
auto print = make_any_method<void(std::ostream&)>(
  [](auto&& self, auto&& os){ os << self; }
);

using printable_any = super_any<decltype(print)>;

printable_any bob = 7; // sets up the printing data attached to the any

int main() {
  (bob->*print)(std::cout); // prints 7
  bob = 3.14159;
  (bob->*print)(std::cout); // prints 3.14159
}

Live

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38835747

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档