Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/tensorflow/5.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++ - Fatal编程技术网

模板化虚函数 我们知道C++不允许在类中使用模板化虚函数。有人知道为什么会有这样的限制吗?

模板化虚函数 我们知道C++不允许在类中使用模板化虚函数。有人知道为什么会有这样的限制吗?,c++,C++,您将如何构造vtable?从理论上讲,模板成员可能有无限多个版本,编译器在创建vtable时可能不知道这些版本是什么。简短回答:虚拟函数是指在运行时,从已编译的候选函数集中选择函数时,才知道谁调用了谁。函数模板OTOH是关于在编译时从调用方创建任意数量的不同函数(使用在编写被调用方时可能还不知道的类型)。这根本不匹配 回答稍微长一点:虚拟函数是使用一个附加的间接寻址(程序员的通用解决方案)实现的,通常作为函数指针表(所谓的虚拟函数表,通常缩写为“vtable”)实现。如果您正在调用虚拟函数,运行

您将如何构造vtable?从理论上讲,模板成员可能有无限多个版本,编译器在创建vtable时可能不知道这些版本是什么。

简短回答:虚拟函数是指在运行时,从已编译的候选函数集中选择函数时,才知道谁调用了谁。函数模板OTOH是关于在编译时从调用方创建任意数量的不同函数(使用在编写被调用方时可能还不知道的类型)。这根本不匹配


回答稍微长一点:虚拟函数是使用一个附加的间接寻址(程序员的通用解决方案)实现的,通常作为函数指针表(所谓的虚拟函数表,通常缩写为“vtable”)实现。如果您正在调用虚拟函数,运行时系统将从表中选择正确的函数。如果存在虚拟函数模板,则运行时系统必须使用精确的模板参数查找已编译模板实例的地址。由于类的设计器无法提供任意数量的函数模板实例,这些实例是由一组无限可能的参数创建的,因此无法工作

我认为编译器可以将vtable偏移量生成为常量(而对非虚函数的引用是修复)

当编译对模板函数的调用时,编译器通常只在二进制文件中放入注释,有效地告诉链接器“请用指向正确函数的指针替换此注释”。静态链接器执行类似的操作,一旦代码加载到内存中并且其地址已知,加载程序最终将填充该值。这称为修复,因为加载程序通过填写所需的数字来“修复”代码。请注意,要生成修复,编译器不需要知道类中还存在哪些其他函数,只需要知道它想要的函数的名称

然而,对于虚拟函数,编译器通常会发出这样的代码:“从对象中取出vtable指针,向其中添加24个,加载函数地址,然后调用它”。为了知道您想要的特定虚拟函数位于偏移量24,编译器需要知道类中的所有虚拟函数,以及它们在vtable中的显示顺序。目前,编译器确实知道这一点,因为所有虚拟函数都列在类定义中。但是,为了在存在模板化虚拟函数的情况下生成虚拟调用,编译器需要在调用时知道函数模板有哪些实例化。它不可能知道这一点,因为不同的编译单元可能会实例化不同版本的函数模板。所以它无法计算在vtable中使用什么偏移量

现在,我怀疑编译器可以通过发出一个整数修饰符(而不是常量vtable offset)来支持虚拟函数模板。也就是说,有一条注释说“请用这个名称填写虚拟函数的vtable偏移量”。然后,静态链接器可能会在知道哪些实例化可用时(在不同编译单元中删除重复模板实例化时)填充实际值。但这将给链接器带来沉重的工作负担,使其无法确定vtable布局,而目前编译器是自己完成这项工作的。模板是特意指定的,以使实现者更容易操作,希望它们在C++0x

因此,我推测,基于这些思路的一些推理导致标准委员会得出结论,虚拟功能模板,即使可以实现,也很难实现,因此不能包含在标准中


注意到,在我试图阅读委员会的思想之前,有一点是很有道理的:我不是C++实现的作者,也不是在电视上玩的。

< P>其他的答案已经提到,在C++中,虚拟函数通常是通过在对象中有一个指针(VPTR)来处理的。坐到桌子旁。此表(vtable)包含指向虚拟成员使用的函数的指针以及一些其他内容

P>另一部分解释是模板通过代码扩展在C++中处理。这允许显式专门化

现在,有些语言要求(Eiffel——我认为Java和C#也是如此,但我对它们的了解不够权威)或允许(Ada)共享泛型处理,没有明确的专门化,但允许虚拟模板函数,将模板放入库中,并可以减少代码大小

通过使用一种称为类型擦除的技术,可以获得共享泛型的效果。这是手动执行共享泛型语言编译器正在执行的操作(好吧,至少其中一些编译器,取决于语言,其他实现技术可能是可能的)。下面是一个(愚蠢的)例子:

#包括
#包括
#ifdef NOT_CPP
C类
{
公众:
虚拟模板int GETANIT(T const&v){
返回getint(v);
}
};
#否则
类内部数据库
{
公众:
虚拟int getTheInt()常量=0;
};
模板
类IntGetter:公共IntGetterBase
{
公众:
IntGetter(T常量和值):myValue(值){}
虚拟int getTheInt()常量
{
返回getint(myValue);
}
私人:
T常数&myValue;
};
模板
IntGetter生成IntGetter(T常量和值)
{
返回IntGetter(值);
}
C类
{
公众:
虚拟整数getanit(整数基常量&v)
{
return v.getTheInt();
#include <string.h>
#include <iostream>

#ifdef NOT_CPP
class C
{
public:
    virtual template<typename T> int getAnInt(T const& v) {
        return getint(v);
    }
};
#else
class IntGetterBase
{
public:
    virtual int getTheInt() const = 0;
};

template<typename T>
class IntGetter: public IntGetterBase
{
public:
    IntGetter(T const& value) : myValue(value) {}
    virtual int getTheInt() const
    {
        return getint(myValue);
    }
private:
    T const& myValue;
};

template<typename T>
IntGetter<T> makeIntGetter(T const& value)
{
    return IntGetter<T>(value);
}

class C
{
public:
    virtual int getAnInt(IntGetterBase const& v)
    {
        return v.getTheInt();
    }
};
#endif

int getint(double d)
{
    return static_cast<int>(d);
}

int getint(char const* s)
{
    return strlen(s);
}

int main()
{
    C c;
    std::cout << c.getAnInt(makeIntGetter(3.141)) + c.getAnInt(makeIntGetter("foo")) << '\n';
    return 0;
}