【问题标题】:Type erasure for methods with differing in return types返回类型不同的方法的类型擦除
【发布时间】:2011-05-22 17:16:09
【问题描述】:

我想知道是否存在某种形式的类型擦除来处理具有相同名称和参数但返回不同值的方法,如下面的示例(beginend)。我不打算在任何地方实际使用它,我只是想知道它是否可能,如果可能,如何完成。

我知道的唯一类型擦除形式是有一个指向纯虚拟concept 类的指针,该类指向一个model<T>,它将调用转发到底层T。但是,这要求所有T 包含具有完全相同签名的方法,而在我的示例中,返回类型不同。据我所知,需要类似于虚拟模板函数的东西来完成我的要求,但我可能会遗漏一些东西。

class Iterable
{
    //how would this be defined?
}

int main(int argc, char *argv[])
{
    vector<int> v = {1, 2, 3, 4, 5};
    set<string> s = {"foo", "bar", "baz"};

    Iterable iterable;

    if(argc == 2) iterable = v;
    else iterable = s;


    for(auto val : it)
    { 
        cout << val << ' ';
    }
}

【问题讨论】:

    标签: c++ c++11 type-erasure


    【解决方案1】:

    类型擦除可以并且已经在 C++ 中的不同上下文中实现。在boost::anystd::function&lt; signature &gt;std::thread 等中使用的最常见的方法是基于一个非多态类,即 type erased 对象,它包含一个指向接口类型。在内部,在构造、赋值期间或每当用户类型被擦除时,都会实例化并存储接口的实现。

    作为一个激励性的简化示例,假设我们想要创建一个 printable 类型,该类型可用于打印使用类型擦除实现 operator&lt;&lt;std::cout 的任何类型。为此,我们需要类型printable、内部接口printable_impl_base,以及实际的实现:

    // regular polymorphic hierarchy:
    struct printable_impl_base {
       virtual ~printable_impl_base() {}
       virtual void print() const = 0;
    };
    template <typename T>
    struct printable_impl : printable_impl_base {
       T copy_to_print;
       printable_impl( T const & o ) : copy_to_print( o ) {}
       virtual void print() const {
          std::cout << copy_to_print << std::endl;
       }
    };
    
    // type erasure is performed in printable:
    class printable {
       std::shared_ptr<printablable_impl_base> p;
    public:
       template <typename T>
       printable( T obj ) : p( new printable_impl<T>(obj) ) {}
       void print() const {
          p->print();
       }
    };
    

    请注意,该模式与常规的多态层次结构非常相似,不同之处在于添加了一个作为值类型的接口对象(借用术语值类型来自 C#),其中包含实际的多态对象。

    这样看,似乎有点简单化和无用,但那是驱动boost::any的燃料(内部接口只是一个typeid),std::function&lt; void () &gt;(内部接口是它实现了@987654333 @),或者shared_ptr&lt;&gt;(接口是deleter方法,放弃资源)。

    当需要对实现类型擦除的类型做的唯一事情是销毁它时,有一种特定的不同类型的类型擦除:使用临时并将其绑定到常量引用......但这非常具体来说,如果您愿意,可以在这里阅读:http://drdobbs.com/cpp/184403758

    在您在问题中谈论的特定情况下,它有点复杂,因为您不想删除单个类型,而是要删除其中的几个。 Iterable 接口必须擦除它内部保存的容器的类型,并且在这样做时它必须提供它自己的迭代器,这些迭代器必须对来自容器的迭代器执行类型擦除。尽管如此,这个想法基本上是相同的,只是需要做更多的工作来实现。

    【讨论】:

      【解决方案2】:

      你可能对boost::any感兴趣:

      http://www.boost.org/doc/libs/1_46_1/doc/html/any.html

      【讨论】:

      • 仅链接的答案对于未来的位腐烂来说是脆弱的,您能否通过一些内容对其进行扩展?
      【解决方案3】:

      C++ 标准库不支持其容器类型的运行时变化。实现这一点并没有错,但是,在语言级别没有垃圾收集的内存管理将是非常棒的,而且你会很开心让它变得高效。

      值得一提的是,在一些 STL 实现中,它们实现了一种称为 SCARY 迭代的东西,其中 vector&lt;int, std::allocator&lt;int&gt;&gt;::iteratorvector&lt;int, mycustomallocator&lt;int&gt;&gt;::iterator 的类型相同。

      此外,您需要非常小心。一个vector肯定是RandomAccessIterable,但是一个set只有ConstIterable而且肯定不是RandomAccessIterable,而一个InputIterator只有ForwardIterable。您必须为所有这些场景定义模板。

      【讨论】:

        猜你喜欢
        • 2020-04-17
        • 2019-04-10
        • 2016-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多