做C ++类模板的显式实例化实例化依赖基类? [英] Do Explicit Instantiations of C++ Class Templates Instantiate Dependent Base Classes?

查看:263
本文介绍了做C ++类模板的显式实例化实例化依赖基类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为一个显式的实例化请求会自动实例化所有的基类成员,但是我得到一个链接器错误:未解析的外部符号public:void Base< int> :: foo(int)使用Visual Studio 2008或2010构建此代码时。



请注意,添加对 foo c $ c> in bar()强制编译器实例化 Base< int> :: bar()编译成功,所以似乎编译器具有实例化 foo()的所有必要的信息。



在source.cpp中显式实例化 Base< int> 允许构建成功,但是显式实例化派生类时,似乎需要显式实例化任何依赖的基类。 / p>

这是正常吗?我找不到标准关于此问题的说法。



header.h

  template< typename T> 
class Base {
public:
void foo();
};

template< typename T>
class Derived:public Base< T> {
public:
void bar();
};

source.cpp

  #includeheader.h

template< typename T>
void Base< T> :: foo(){}

template< typename T>
void Derived< T> :: bar(){
// this-> foo(); //添加这个强制实例化foo()???
}

模板类Derived< int> ;;

main.cpp

  #includeheader.h

int main(){
Derived< int& d;
d.foo(); // Linker Error:unresolved external symbolpublic:void Base< int> :: foo(int)
}

编辑:



看起来像标准说的只有一个类的成员通过显式类实例化来实例化,



请注意,类是由class-head {member-specification}定义的,类定义中的成员规范声明类的成员的完整集合;没有成员可以在别处添加。所以成员只在大括号{}之间,公共基类成员不会成为派生类的成员,它们只能从派生类或派生类的对象访问。



我唯一剩下的问题是为什么标准规定一个类模板的显式实例化只实例化成员而不是基类的成员?我的猜测是,这允许更多的控制什么获得显式实例化在哪里。使用显式模板类实例化的人最有可能将基类定义放在与派生类定义不同的文件中,并且将单独显式实例化每一个。

解决方案

标准表示


类模板特化的显式实例化意味着实例化其以前没有的所有成员显式专门化包含显式实例化的翻译单元。


换句话说,它不要求基类。它将导致它们的隐式实例化,它们不会预先实例化它们的成员定义。在标准中有一些丑陋的错误,是否某些文字是成员是指直接或继承成员,因为这通常似乎是显而易见的人写了标准的措辞,但不是一个读它的人。 C ++ 0x添加了一些澄清(它也有显式实例化声明定义之间的区别C ++ 03没有,但即使忽略, C ++ 0x字样包含一些更多的洞察):


明确的实例化命名一个类模板专门化也是一个显式实例化
它的每个成员(声明或定义)的每个成员(不包括继承自基本
类的成员),以前没有明确专门在翻译单元包含显式
实例化,除非如下所述。 [注意:此外,它通常是一个明确的实例化
某些与实现相关的类的数据。 - end note]



I figured an explicit instantiation request would automatically instantiate all base class members also, but I get a linker error: unresolved external symbol "public: void Base<int>::foo(int)" when building this code using Visual Studio 2008 or 2010.

Note that adding a call to foo() inside bar() forces the compiler to instantiate Base<int>::bar() and the build succeeds, so it appears that the compiler has all the necessary information to instantiate foo().

Obviously, explicitly instantiating Base<int> in source.cpp allows the build to succeed, but it seems silly to need to explicitly instantiate any dependent base classes whenever explicitly instantiating a derived class.

Is this normal? I couldn't find what the standard says regarding this issue.

header.h

template<typename T>
class Base {
public:
    void foo();
};

template<typename T>
class Derived : public Base<T> {
public:
    void bar();
};

source.cpp

#include "header.h"

template<typename T>
void Base<T>::foo() { }

template<typename T>
void Derived<T>::bar() {
    // this->foo();   // adding this forces instantiation of foo()???
}

template class Derived<int>;

main.cpp

#include "header.h"

int main() {
    Derived<int> d;
    d.foo(); // Linker Error: unresolved external symbol "public: void Base<int>::foo(int)"
}

Edit:

It looks like the Standard says only members of a class get instantiated by an explicit class instantiation, so the linker error is justified in my example.

Note that a class is defined by class-head { member-specification } and "The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere." So members are only between the curly braces { }, and public base class members don't become members of the derived class, they are merely accessible from the derived class or by objects of the derived class.

My only remaining question is why the Standard specifies that explicit instantiation of a class template only instantiates members and not members of base classes? My guess is that this allows greater control of what gets explicitly instantiated where. Someone that's using explicit template class instantiations would most likely have the base class definitions in a different file than the derived class definitions, and would explicitly instantiate each separately.

解决方案

The Standard says

The explicit instantiation of a class template specialization implies the instantiation of all of its members not previously explicitly specialized in the translation unit containing the explicit instantiation.

In other words, it does not mandate that base classes are explicitly instantiated in turn. It will cause an implicit instantiation of them which will not instantiate their member definitions up-front. It's some ugly glitch in the Standard as to whether some text when it says "member" means "direct" or "inherited" member, as that often seems to be "obvious" to the one who wrote the Standards wording, but not to the one who reads it. C++0x has added some clarifications (it also has a difference between explicit instantiation declarations and definitions that C++03 doesn't have, but even ignoring that, the C++0x wording contains some more bits of insight):

An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below. [ Note: In addition, it will typically be an explicit instantiation of certain implementation-dependent data about the class. — end note ]

这篇关于做C ++类模板的显式实例化实例化依赖基类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆