GCC和MS编译器的模板实例化详细信息 [英] Template instantiation details of GCC and MS compilers

查看:190
本文介绍了GCC和MS编译器的模板实例化详细信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以提供模板实例化
在GCC和MS编译器中在编译和/或链接时间处理的比较或具体细节?在静态库,共享库和可执行文件的上下文中,这个过程是不同的

我找到此文档关于GCC如何处理它,但我不知道如果信息
仍然指的是事物的当前状态。我应该使用标志
他们建议那里编译我的库,例如。 -fno-implicit-templates



我知道(可能不一定正确):




  • 模板将在实际使用时实例化

  • 模板将通过显式实例化实例化

  • 重复实例化通常是通过折叠重复实例化或延迟实例化直到链接时间来处理


解决方案




实例化点




模板将在实际使用时实例化


不完全是,但粗略。实例化的精确点有点微妙,我将您委托到名为 Vandevoorde / Josuttis的高级书中的实例化点。



但是,编译器不一定正确实施POI: Bug c ++ / 41995:不正确功能模板的实例化点






部分实例化




模板将在实际使用时实例化


这是部分正确的。它对于函数模板是正确的,但对于类模板,只有使用的成员函数被实例化。以下是格式正确的代码:

  #include< iostream> 

template< typename> struct Foo {
void let_me_stay(){
this-> is-> valid-> code。 get-> off-> my->草坪;
}

void fun(){std :: cout< fun()< std :: endl; }
};


int main(){
Foo< void> foo;
foo.fun();
}

let_me_stay()





在语法上检查语法

两阶段查找



然而,只有依赖代码显然,在 Foo <<> 之内取决于 Foo<<> 被实例化,因此我们推迟了 Foo let_me_alone()的错误检查直到实例化时间。 p>

但是如果我们不使用取决于具体实例化的东西,代码必须是好的。因此,以下是格式正确的:

  $ cat non-dependent.cc 
template< typename> struct Foo {
void I_wont_compile(){Mine-> is-> valid-> code。 get-> off-> my->草坪; }
};
int main(){} //注意:没有单实例化

Mine 是一个完全未知的符号给编译器,不像 this ,编译器可以确定它的实例依赖。



这里的关键是C ++使用的模型两阶段查找,其中它检查第一依赖代码的阶段和语义检查是在阶段二(和实例化时间)完成的(这也是一个经常被误解或未知的概念,许多C ++程序员假设模板在实例化之前一直不被解析,但这只是神话来自, ...,Microsoft C ++)。






类模板的完全实例化



Foo<> :: let_me_stay()的定义因为错误检查被推迟到以后, code> this 指针,它是从属的。除非您使用了


显式实例化




  cat> foo.cc 
#include< iostream>

template< typename> struct Foo {
void let_me_stay(){this-> is-> valid-> code。 get-> off-> my->草坪; }
void fun(){std :: cout<< fun()< std :: endl; }
};

template struct Foo< void> ;;
int main(){
Foo< void> foo;
foo.fun();
}

g ++ foo.cc
错误:error:'struct Foo< void>'没有成员命名'is'






不同翻译单位的模板定义



当您显式实例化时,将显式实例化。并使所有符号对链接程序可见,这也意味着模板定义可能位于不同的翻译单位:

  $ cat A.cc 
template< typename> struct Foo {
void fun(); //注意:没有定义
};
int main(){
Foo< void>()。fun();
}

$ cat B.cc
#include< iostream>
template< typename> struct Foo {
void fun();

};
template< typename T>
void Foo< T> :: fun(){
std :: cout< 有趣! << std :: endl;
} //注意:使用extern链接的定义

template struct Foo< void> //在void之后显式实例化

$ g ++ A.cc B.cc
$ ./a.out
fun!

但是,必须显式实例化所有要使用的模板参数,否则

  $ cat A.cc 
template< typename> struct Foo {
void fun(); //注意:没有定义
};
int main(){
Foo< float>()。fun();
}
$ g ++ A.cc B.cc
未定义的引用`Foo< float> :: fun()'






有关两阶段查找的小注意事项:编译器是否实际实现两阶段查找不是由标准决定的。然而,为了符合,它应该像它一样工作(就像加法或乘法不一定必须使用加法或乘法CPU指令来执行)。


Could anyone provide a comparison or specific details of how is template instantiation handled at compile and/or link time in GCC and MS compilers? Is this process different in the context of static libraries, shared libraries and executables? I found this doc about how GCC handles it but I'm not sure if the information is still referring to the current state of things. Should I use the flags they suggest there when compiling my libraries e.g. -fno-implicit-templates?

What I know (might not necessarily be correct) is that:

  • templates will be instantiated when actually used
  • templates will be instantiated as a result of explicit instantiations
  • duplicate instantiation is usually handled by folding duplicate instantiations, or by deferring instantiation until link time

解决方案


Point of instantiation

templates will be instantiated when actually used

Not exactly, but roughly. The precise point of instantiation is a bit subtle, and I delegate you over to the section named Point of instantiation in Vandevoorde's/Josuttis' fine book.

However, compilers do not necessarily implement the POIs correctly: Bug c++/41995: Incorrect point of instantiation for function template


Partial instantiation

templates will be instantiated when actually used

That is partially correct. It is true for function templates, but for class templates, only the member functions that are used are instantiated. The following is well-formed code:

#include <iostream>

template <typename> struct Foo {
    void let_me_stay() {
        this->is->valid->code. get->off->my->lawn;
    }

    void fun() { std::cout << "fun()" << std::endl; } 
};


int main () {
    Foo<void> foo;
    foo.fun();
}

let_me_stay() is checked syntactically (and the syntax there is correct), but not semantically (i.e. it is not interpreted).


Two phase lookup

However, only dependent code is interpreted later; clearly, within Foo<>, this is dependent upon the exact template-id with which Foo<> is instantiated, so we postponed error-checking of Foo<>::let_me_alone() until instantiation time.

But if we do not use something that depends on the specific instantiation, the code must be good. Therefore, the following is not well-formed:

$ cat non-dependent.cc
template <typename> struct Foo {
    void I_wont_compile() { Mine->is->valid->code. get->off->my->lawn; }
};
int main () {} // note: no single instantiation

Mine is a completely unknown symbol to the compiler, unlike this, for which the compiler could determine it's instance dependency.

The key-point here is that C++ uses a model of two-phase-lookup, where it does checking for non-dependent code in the first phase, and semantic checking for dependent code is done in phase two (and instantiation time) (this is also an often misunderstood or unknown concept, many C++ programmers assume that templates are not parsed at all until instantiation, but that's only myth coming from, ..., Microsoft C++).


Full instantiation of class templates

The definition of Foo<>::let_me_stay() worked because error checking was postponed to later, as for the this pointer, which is dependent. Except when you would have made use of

explicit instantiations

cat > foo.cc
#include <iostream>

template <typename> struct Foo {
    void let_me_stay() { this->is->valid->code. get->off->my->lawn; }
    void fun() { std::cout << "fun()" << std::endl; } 
};

template struct Foo<void>;
int main () {
    Foo<void> foo;
    foo.fun();
}

g++ foo.cc
error: error: ‘struct Foo<void>’ has no member named ‘is’


Template definitions in different units of translation

When you explicitly instantiate, you instantiate explicitly. And make all symbols visible to the linker, which also means that the template definition may reside in different units of translation:

$ cat A.cc
template <typename> struct Foo {
    void fun();  // Note: no definition
};
int main () {
    Foo<void>().fun();
}

$ cat B.cc
#include <iostream>
template <typename> struct Foo {
    void fun();

};
template <typename T>
void Foo<T>::fun() { 
    std::cout << "fun!" << std::endl;
}  // Note: definition with extern linkage

template struct Foo<void>; // explicit instantiation upon void

$ g++ A.cc B.cc
$ ./a.out
fun!

However, you must explicitly instantiate for all template arguments to be used, otherwise

$ cat A.cc
template <typename> struct Foo {
    void fun();  // Note: no definition
};
int main () {
    Foo<float>().fun();
}
$ g++ A.cc B.cc
undefined reference to `Foo<float>::fun()'


Small note about two-phase lookup: Whether a compiler actually implements two-phase lookup is not dictated by the standard. To be conformant, however, it should work as if it did (just like addition or multiplication do not necessarily have to be performed using addition or multiplication CPU instructions.

这篇关于GCC和MS编译器的模板实例化详细信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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