使用类型抹除来创建运行时type_traits查询

5

是否有可能使用类型擦除来创建封装任意类型(称为ErasedType)的对象,并可以在运行时查询以确定另一个任意类型T是否可转换为ErasedType

经过思考,我认为这不可能-即使理论上似乎有可能。编译器会知道我们正在尝试与ErasedType进行比较的哪些类型T,因此可以在运行之前生成必要的代码。问题在于,在实践中,似乎没有任何方法将模板参数类型从基类实例传递到子类实例。

例如:

struct FooBase
{
    template <class TestType>
    bool is_convertible()
    {
        return call_derived();
    }

    protected:

    virtual bool call_derived() = 0;

    template <class ErasedType>
    void base_class_function() { }
};

template <class ErasedType>
struct Foo : public FooBase
{
    bool call_derived()
    {
        // Here we have access to the ErasedType but no access to TestType.
            //
        // We could pass ErasedType to a base class function by saying:
        //
        // this->base_class_function<ErasedType>();
        //
        // ...but that doesn't seem to help since we still don't have access to
        // TestType
    }
};

所以,目标是能够说出类似这样的话:
FooBase* f = new Foo<int>();
bool res1 = f->is_convertible<double>(); // returns true
bool res2 = f->is_convertible<long>(); // returns true
bool res3 = f->is_convertible<std::string>(); // returns false

但是,我看不出如何实现FooBase::is_convertible方法,因为我看不到在同一个函数中使TestTypeErasedType可访问的方法,以便编译器可以计算std::is_convertible<TestType, ErasedType>::value的结果。

那么,这是否有可能呢?


1
您的类型擦除基类可以公开一个虚函数,该函数提供具体类型的 type_id ……但是特征是编译时构造,不会真正与动态类型交互。 - Kerrek SB
@KerrekSB:虽然你可以在运行时使用该信息构建查找结构,并在运行时查询它,但另一种选择是在类型擦除上伪造双重分派以传递“可转换”检查器... 任何一种方法都需要相当多的样板代码,并且不会完全通用。 - David Rodríguez - dribeas
@David,即使使用双重分发,每当调用多态函数时仍会丢失模板参数,那么你如何安排TestTypeErasedType都不被隐藏的情况呢? - Channel72
@Channel72:这就是为什么我评论说你需要大量的“样板文件”,与其他方法的区别在于,你可以在擦除类型上实现测试...如果有足够的时间,你可以通过特征类以类型列表的形式实现它。评论中的“不完全通用”部分是因为它只会选择该列表/查找中由你定义的转换。 - David Rodríguez - dribeas
这里的(普遍)问题是,您想要关于类型的二次数据量(鉴于您无法访问编译器的内部线性数据量),但虚拟/模板机制只能生成线性数量的数据(可以通过考虑每个类型参数仅在其自己的翻译单元中定义的情况来看到)。 - Davis Herring
1个回答

2
在C++中,通常情况下确实不可能做到这一点。要在运行时对类型进行任意查询需要相当多的元数据,而C++试图将其保持最小化(有时甚至到了有点烦人的地步;一个功能可以在使用时自动选择加入,因此没有不必要的开销,但我岔开了话题)。
正如David所暗示的那样,完全自动地复制编译器信息是完全可能的,但只能达到一定程度。这限制了运行时类型信息仅限于您手动添加的内容。
看看像Qt这样的库,它在C++之上提供了整个框架以提供这些元数据,以了解涉及的工作类型。根据手头的问题,您可能可以不用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接