Chinaunix

标题: gcc4.1对模板实例化的支持有问题??问题已解决,感谢大家的回答,特别是 whyglinux [打印本页]

作者: xiaoligang    时间: 2007-01-29 14:10
标题: gcc4.1对模板实例化的支持有问题??问题已解决,感谢大家的回答,特别是 whyglinux
这段代码在gcc version 4.1.0 20060304 (Red Hat 4.1.0-3)
以及 gcc version  4.1.1 20061011 (Red Hat 4.1.1-30)都编译不过去
// main.cpp
#include <iostream>       

using namespace std;

       
void print(const char *){}

template <typename Type>
        Type sum(Type op1, int op2)
        {
                cout << "Type sum(Type op1, int op2)" << endl;
                print("ggggggggg");
                print(op1);
                return op1;
        }

void print(int a){}       

int main(int argc, char **argv)
{
        sum(8, 10);

        return 0;
}

// 实例化点
/***************************
int sum<int>(int, int)
{
   .........
}

***************************/

在gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)编译及运行都很好。


对有些人的回答不再理会以免其在这里灌水



编译指令 g++ main.cpp



对于认为 在模板定义中所有用到的函数都要要首先声明的请看

c++primer 第三版 10.9 模板定义中的名字解析

节的解释。

我发现了这个问题,就从c++primer上抄了这段代码,结果真的不行。





问题已解决,感谢大家的回答,特别是 whyglinux 的耐心的解释 如下:

我在上面回答 xiaoligang 提出的这个问题的时候,其实还没有真正了解问题的实质,所以可忽略我上面的回答,请参见下面的回答:

对于依赖模板参数的函数的解析问题,在原来 C++ 98 标准的基础上根据下面的一个缺陷报告进行了一些修正。

197. Issues with two-stage lookup of dependent names

也就是说,在《C++ Primer 3》中的有关叙述对于模板参数是基本类型的情况已经过时了。

当传入模板函数的模板参数是一个基本类型(fundamental type)的时候,由于基本类型不具有关联名字空间和类域(associated namespaces and classes),所以没有额外的空间进行名字查找,只进行默认的名字查找(其搜索范围是在名字被使用之前),因此要求在使用之前要有函数的声明存在。

如果模板参数是非基本类型,比如是一个类类型,则除了默认的查找范围外,还可以查找这个类的类域以及这个类所在的名字空间等关联空间。所以,函数的声明无论是在类定义之前还是之后都处于名字搜索空间内都可以被找到。

根据上面的分析可知:楼主的程序是一个不正确的程序,因为 print(int) 将永远也不会被找到,当然也不会被调用。唯一能找到的函数声明是在使用 print 之前出现的 print(const char *)。显然,当函数模板参数类型和 const char * 不一致的时候一般会导致编译错误。

新版的 GCC 编译器遵循了这一新的 C++ 标准的规定,而旧版的没有,也就出现了两种不同的编译结果。



[ 本帖最后由 xiaoligang 于 2007-1-30 09:42 编辑 ]
作者: tyc611    时间: 2007-01-29 14:19
你程序本身有问题:
sum(8, 10);表明你的print(op1);中op1为int,而print的参数类型是const char*,显然类型不匹配
作者: tyc611    时间: 2007-01-29 14:19
随便说一句,少加那么多与问题无关的符号
作者: xiaoligang    时间: 2007-01-29 14:30
to tyc611:
程序本身没问题,请看模版实例化点的资料!!!!!!!!!!
main()
{
}
请注意实例化点在这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

[ 本帖最后由 xiaoligang 于 2007-1-29 14:33 编辑 ]
作者: tyc611    时间: 2007-01-29 14:36
原帖由 xiaoligang 于 2007-1-29 14:30 发表
to tyc611:
程序本身没问题,请看模版实例化点的资料!!!!!!!!!!
main()
{
}
请注意实例化点在这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

把编译错误信息贴出来

PS:少用那么多感叹号
作者: xiaoligang    时间: 2007-01-29 14:43
原帖由 tyc611 于 2007-1-29 14:36 发表

把编译错误信息贴出来

PS:少用那么多感叹号

能够引起高人的注意,多用点!?也是值得的!!!!!!!!!!!!!

main.cpp: In function ‘Type sum(Type, int) [with Type = int]’:
main.cpp:21:   instantiated from here
main.cpp:13: 错误:从类型 ‘int’ 到类型 ‘const char*’ 的转换无效
main.cpp:13: 错误:  初始化实参 1,属于 ‘void print(const char*)’

[ 本帖最后由 xiaoligang 于 2007-1-29 14:44 编辑 ]
作者: tyc611    时间: 2007-01-29 14:45
原帖由 xiaoligang 于 2007-1-29 14:43 发表


main.cpp: In function ‘Type sum(Type, int) [with Type = int]’:
main.cpp:21:   instantiated from here
main.cpp:13: 错误:从类型 ‘int’ 到类型 ‘const char*’ 的转换无效
main.cpp:13: 错误: ...

原因在二楼我的解释
作者: tyc611    时间: 2007-01-29 14:46
标题: 回复 6楼 xiaoligang 的帖子
能够引起高人的注意,多用点!?也是值得的!!!!!!!!!!!!!

很不幸地告诉你:这儿的人不喜欢那么多的标点符号
作者: Edengundam    时间: 2007-01-29 15:24
g++
作者: xiaoligang    时间: 2007-01-29 15:28
原帖由 Edengundam 于 2007-1-29 15:24 发表
g++



是g++
作者: whyglinux    时间: 2007-01-29 16:08
使用函数之前必须要首先声明。你的程序没有做好这一点,也就是说程序中还有问题存在。

在旧版的 GCC 中编译通过而在新版的 GCC 中编译不通过,说明新版 GCC 对非法程序的检查更加彻底一些。
作者: xiaoligang    时间: 2007-01-29 16:47
原帖由 whyglinux 于 2007-1-29 16:08 发表
使用函数之前必须要首先声明。你的程序没有做好这一点,也就是说程序中还有问题存在。

在旧版的 GCC 中编译通过而在新版的 GCC 中编译不通过,说明新版 GCC 对非法程序的检查更加彻底一些。


并不是这个问题,对于模版库的设计者,
他不知道你会用什么样的类型去实例化模版函数,
也就是说要在模板定义的前面声名所有类型的函数调用是不可能。

就像我们要对自己的类型特化模板一样。对于自己定义的类,结构,设计者不可能会知道。


你可以想一想你在用stl中的模板的时候

是把对于你自己的定义的类的操作符号重载写到了,你所调用的模板定义的前面了吗?

比如 class test{...}; map<test> mapTest;


[ 本帖最后由 xiaoligang 于 2007-1-29 16:54 编辑 ]
作者: whyglinux    时间: 2007-01-29 17:21
>> 并不是这个问题,对于模版库的设计者,
>> 他不知道你会用什么样的类型去实例化模版函数,

是这样的。

>> 也就是说要在模板定义的前面声名所有类型的函数调用是不可能。

怎么不可能?模板是做什么用的?

>> 你可以想一想你在用stl中的模板的时候
>> 是把对于你自己的定义的类的操作符号重载写到了,你所调用的模板定义的前面了吗?
>> 比如 class test{...}; map<test> mapTest;

实在是没看明白你的意思。
作者: xiaoligang    时间: 2007-01-29 17:27
我在顶楼写了这么一段话。

请您参考

“对于认为 在模板定义中所有用到的函数都要要首先声明的请看

c++primer 第三版 10.9 模板定义中的名字解析

节的解释。”
作者: whyglinux    时间: 2007-01-29 23:46
我在上面回答 xiaoligang 提出的这个问题的时候,其实还没有真正了解问题的实质,所以可忽略我上面的回答,请参见下面的回答:

对于依赖模板参数的函数的解析问题,在原来 C++ 98 标准的基础上根据下面的一个缺陷报告进行了一些修正。

197. Issues with two-stage lookup of dependent names

也就是说,在《C++ Primer 3》中的有关叙述对于模板参数是基本类型的情况已经过时了。

当传入模板函数的模板参数是一个基本类型(fundamental type)的时候,由于基本类型不具有关联名字空间和类域(associated namespaces and classes),所以没有额外的空间进行名字查找,只进行默认的名字查找(其搜索范围是在名字被使用之前),因此要求在使用之前要有函数的声明存在。

如果模板参数是非基本类型,比如是一个类类型,则除了默认的查找范围外,还可以查找这个类的类域以及这个类所在的名字空间等关联空间。所以,函数的声明无论是在类定义之前还是之后都处于名字搜索空间内都可以被找到。

根据上面的分析可知:楼主的程序是一个不正确的程序,因为 print(int) 将永远也不会被找到,当然也不会被调用。唯一能找到的函数声明是在使用 print 之前出现的 print(const char *)。显然,当函数模板参数类型和 const char * 不一致的时候一般会导致编译错误。

新版的 GCC 编译器遵循了这一新的 C++ 标准的规定,而旧版的没有,也就出现了两种不同的编译结果。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2