A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© ZXY66452 中级黑马   /  2015-12-5 21:52  /  593 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

由于泛型能够使我们更高效、合理地管理好自己的代码,同时也为部件化提供了许多便利之处。那么Blocks与泛型结合会产生什么新元素呢?
我们先举一个简单例子:
#import <Foundation/Foundation.h>

template <void pBlock(void)>
void BlockTest(void)
{
    pBlock();
}

void Hi(void)
{
    NSLog(@"Hi, there!");
}

int main(int argc, const char* argv[])
{
    BlockTest<Hi>();
}
上述代码中尚未出现Blocks,但是我们可以看到,一般的外部函数能够作为模板参数。那么Blocks是否可以这么做呢?我们不妨尝试一下:
#import <Foundation/Foundation.h>

template <void (^pBlock)(void)>
void BlockTest(void)
{
    pBlock();
}

int main(int argc, const char* argv[])
{
    BlockTest<^(void) { NSLog(@"Hi, there!"); }>();
}
编译时会在第11行出现error: no matching function for call to \'BlockTest()\'。C++标准中明确指出,模板参数必须为常量表达式,如果是函数的话必须是带有外部连接(即external-linkage)的函数指针。而Blocks表达式首先 就不是一个常量表达式,然后它也没有外部连接。我们下面看第二个例子:
#import <Foundation/Foundation.h>

template <typename T>
void BlockTest(void (&pBlock)(T))
{
    pBlock(T());
}

static void Hi(int a)
{
    NSLog(@"The value is: %dn", a);
}

int main(int argc, const char* argv[])
{
    BlockTest(Hi);
}
上述代码中使用了函数引用作为函数参数,然后由实参类型演绎出模板类型。这段代码将能正常地通过编译、连接并正常运行。那么我们下面再看一看 Blocks是否具有这个泛型特性:
#import <Foundation/Foundation.h>

template <typename T>
void BlockTest(void (^pBlock)(T))
{
    pBlock(T());
}

int main(int argc, const char* argv[])
{
    BlockTest(^(int a) { NSLog(@"The value is: %dn", a); });
}
编译后出现 error: no matching function for call to \'BlockTest(void (^)(int))\'。即使显式地将<int>模板实参加上也没用。也就是说Blocks的参数类型包括返回类型不能是一个泛型。我们再看第三个例子:
#import <Foundation/Foundation.h>
#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
void BlockTest(T pBlock)
{
    pBlock();
    cout << "The type is: " << typeid(T).name() << endl;
}

static void Hi(void)
{
    NSLog(@"Hi, there!");
}

int main(int argc, const char* argv[])
{
BlockTest(Hi);
}
这段代码展示了整个函数指针类型演绎出模板实参。对于目前已被很多编译器所实现的Lambda表达式,这是与泛型挂钩的唯一桥梁,那么Blocks是否具备这个特性呢?
#import <Foundation/Foundation.h>
#include <iostream>
#include <typeinfo>
using namespace std;

template <typename T>
void BlockTest(T pBlock)
{
    pBlock();
    cout << "The type is: " << typeid(T).name() << endl;
}

int main(int argc, const char* argv[])
{
    BlockTest(^(void) { NSLog(@"Hi, there!"); });
}
恭喜,我们成功了。这段代码能够正常编译和运行。各位可以自己看看输出结果。其中,类型信息是被压缩过的:F表示函数,P表示指针,v表示void类型。Blocks 与C++0x中的lambda表达式一样,必须作为一个完整的类型。对其类型做拆分进行泛型化是非法的。由于C++0x的Lambda表达式的具体类型不对程序员开放,因此它即不能作为模板形参亦无法作为模板函数的形参,但是它可以在模板函数内使用泛型。


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马