可冰

冰,是沉睡着的水......

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  37 随笔 :: 5 文章 :: 94 评论 :: 0 Trackbacks
看了cpunion写的IDL的代码,我知道了这样的用法:
在模板参数中,类型参数可以这样构造:
        template_class< type( type1, type2, ... ) > a_class;
比如,可以void( void ), void(), void( int ), 也可以int( void ), string( int )等等,编译器是将它们当作不同的类型的来处理的.对此,我写了一些代码作了一下测试(见文末).但我也仅仅是有一个感性的认识而已,对于其为什么可以这样(因为从未见哪本书上介绍过这样的用法),我一点也不知道.
希望大家帮我释疑,也希望cpunion来帮我一下,谢谢!


#include 
<iostream>

typedef 
void(*fun)(int);

using namespace std;

template
< typename T >
struct Base
{
    
void test()
    
{
        cout 
<< "Base" << "\t=\t";
        cout 
<< "Base<" << typeid(T).name() << ">" << endl;
    }

}
;

template
<>
struct Base < void >
{
    
void test()
    
{
        cout 
<< "Base" << endl;
    }

}
;

template
<>
struct Base < voidint ) >
{
    
void test()
    
{
        cout 
<< "Base" << endl;
    }

}
;

template
<>
struct Base < fun >
{
    
void test()
    
{
        cout 
<< "Base" << endl;
    }

}
;

template
<>
struct Base < intstringintchar ) >
{
    
void test()
    
{
        cout 
<< "Base" << endl;
    }

}
;

int main(int argc, char* argv[])
{
    Base
< void > b_void;
    Base
< voidint ) > b_void_int;
    b_void.test();
    b_void_int.test();

    Base
< intstringintchar ) > b_int;
    Base
< fun > b_fun;
    b_int.test();
    b_fun.test();


    Base
< Base< void > ( Base < int ( stringintchar ) > ) > b_complex;
    b_complex.test();

    
return 0;
}


posted on 2005-09-29 19:51 可冰 阅读(2193) 评论(9)  编辑 收藏 引用 所属分类: C++

评论

# re: 关于模板的类型参数 2005-09-29 21:16 cpunion
模板的类型参数,只要是类型都是可以接受的。

template <class T>
class Base
{
};
定义了一个类模板,后面都是它的偏特化。

你的疑问应该是void(*)(int)类型和void(int)类型的区别吧?

void(int)是一个函数类型,void(*)(int)是一个函数指针类型,函数类型仅在声明时有效,当把void(int)类型的函数作为一个值来传递时,它自动退化为void(*)(int)指针类型。

关于这一点,最好是看刘未鹏对于boost::function源代码的解释,我也是从这里才知道有这种用法的。  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-29 21:23 函数类型
void Fun(int);
cout << typeid(void(int)).name() << endl;
cout << typeid(Fun).name() << endl;
  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-29 21:39 cpunion
typeid, sizeof, typeof(c++0x)都不取表达式的值,只提取类型。  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-29 22:57 可冰
void(int)原来是函数类型啊!从来没有见到过这样的类型啊.
你所说的"当把void(int)类型的函数作为一个值来传递时,它自动退化为void(*)(int)指针类型。"应该是指,用它来定义变量的时候,这个变量就成了函数指针类型的了?  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-29 23:08 cpunion
函数类型可以用做声明,也可以表示函数代码块,不能直接用它声明一个变量,所以很少见。

比如函数:

void func(int)
{
}

func本身是函数类型,不过当作值来传递给一个void(*)(int)类型指针时,自动退化为指针类型,所以不需要加上&符号,加上&也是合法的。

使用typeid, typeof都可以获取到函数类型。  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-29 23:11 可冰
我在模板中试了一下,确实用函数类型定义的变量成为了函数指针类型.
定义为: T var;
输出为: var: void (__thiscall Base<void __cdecl(int)>::*)(int)
T : void __cdecl(int)

但是在外部,定义这样的一个类型及变量:
typedef void MethodType (int);
MethodType method;

它们的类型居然是一样的,method在这儿并没有转化为函数指针类型.
输出类型如下:
void __cdecl(int)
void __cdecl(int)

这又是怎么回事?  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-29 23:40 cpunion
在g++编译器下,T var;是不能编译通过的。

typedef void MethodType (int);
MethodType method;

这个定义确实能够通过编译(我以前没这么测试过),因为method的是函数类型,而它没有实际定义,相当于写了一个函数声明,所以如果调用它,链接器将报错。

这个功能本来是开放给编译器使用的,所以虽然能够定义,但无法操作它,你无法对它使用sizeof,无法对它取地址,只能对它使用typeid获取类型信息、使用typeof获取它的类型。

int m;
typedef void MethodType (int);
MethodType method;
int n;

测试可以知道,n和m的地址相差是4字节(32位平台上),method并不真的定义了一个变量。

应该是C++给编译器定的标准,相当诡异。。  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-30 01:59 说得对,仅仅是申明
typedef void MethodType (int);
MethodType method;

extern void method(int);
基本上一样,另外,加上定义
void method(int)
{
}
可以
method(0);
这样用了
  回复  更多评论
  

# re: 关于模板的类型参数 2005-09-30 20:51 可冰
[摘录]Boost源码剖析之:泛型函数指针类boost::function(修订版)
刘未鹏 /文

或许你会对模板参数int(int)感到陌生,其实它是个函数型别——函数g的确切型别就是int(int),而我们通常所看到的函数指针型别int (*)(int)则是&g的型别。它们的区别与联系在于:当把g作为一个值进行拷贝的时候(例如,按值传参),其类型就会由int(int)退化为int(*)(int),即从函数类型退化为函数指针类型——因为从语义上说,函数不能被“按值拷贝”,但身为函数指针的地址值则是可以被拷贝的。另一方面,如果g被绑定到引用,则其类型不会退化,仍保持函数类型。
......
请注意,函数类型乃是个极其特殊的类型,在大多数时候它都会退化为函数指针类型,以便满足拷贝语义,只有面对引用绑定的时候,能够维持原来的类型。当然,对于boost::function,总是按值拷贝。  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理