Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用类型擦除创建运行时类型查询_C++_Templates_Type Erasure - Fatal编程技术网

C++ 使用类型擦除创建运行时类型查询

C++ 使用类型擦除创建运行时类型查询,c++,templates,type-erasure,C++,Templates,Type Erasure,是否可以使用类型擦除来创建封装任意类型的对象(我们称之为ErasedType),并且可以在运行时查询以确定另一个任意类型T是否可转换为ErasedType 经过思考,我认为这是不可能的——尽管从理论上看这似乎是可能的。编译器将知道我们试图与ErasedType比较的T类型,因此可以在运行前生成必要的代码。问题是,在实践中,似乎没有任何方法可以将模板参数类型从基类实例传递到子类实例 例如: struct FooBase { template <class TestType>

是否可以使用类型擦除来创建封装任意类型的对象(我们称之为
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
    }
};
structfoobase
{
模板
布尔是可兑换的
{
返回调用_派生();
}
受保护的:
虚拟布尔调用_派生()=0;
模板
void基类函数(){}
};
模板
结构Foo:公共FooBase
{
bool调用_派生()
{
//在这里,我们可以访问ErasedType,但不能访问TestType。
//
//我们可以通过以下方式将ErasedType传递给基类函数:
//
//此->基本类函数();
//
//…但这似乎没有帮助,因为我们仍然无法访问
//测试类型
}
};


因此,我们的目标是能够说:

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*f=newfoo();
bool res1=f->is_convertible();//返回true
bool res2=f->is_convertible();//返回true
bool res3=f->is_convertible();//返回false
但是,我看不出
FooBase::is_convertible
方法是如何实现的,因为我看不到任何方法可以在同一个函数中同时访问
TestType
ErasedType
,因此编译器可以计算
std::is_convertible::value


<> P> >这是不是可能?

,C++中一般是不可能的。在运行时,需要相当多的元数据来对类型进行任意查询,C++试图保持这一最小值(有时会有点恼人;一个特性可以自动选择在使用中使用,因此没有多余的开销,但我不同意)。 正如David所暗示的,完全可以复制编译器信息到某一点,但永远不会完全自动复制。这将运行时类型信息限制为手动添加的信息


看看像这样的库有一个完整的C++框架来提供元数据,看看什么样的工作。根据手头的问题,您可能可以不使用它。

您的类型擦除基类可以公开一个虚拟函数,该函数为您提供具体类型的
类型id
。。。但traits是一种编译时构造,它并没有真正和动态类型交互。@KerrekSB:。。。尽管您可以在运行时使用该信息构建查找结构。。。并在运行时查询。另一种选择是在类型擦除上假装双重分派以通过“可转换”检查器。。。它们中的任何一个都需要相当多的样板代码,并且不是完全通用的。@David,即使使用双重分派,只要调用多态函数,模板参数仍然会丢失,那么,您如何安排
TestType
ErasedType
都不隐藏的情况呢?@Channel72:这就是为什么我评论说您需要大量的样板文件,与其他方法的区别在于您可以对擦除类型执行测试。。。如果有足够的时间,您可以通过traits类中的类型列表来实现这一点。注释中不完全通用的部分是因为它只会选择您在该列表/查找中定义的转换。这里的(常见)问题是您需要关于类型的二次数据量(假设您无法访问编译器内部的线性数据量)但是虚拟/模板机制只能生成线性数量(通过考虑每个类型参数仅在其自己的翻译单元中定义的情况可以看出)。