C++ 头文件系列(system_error)

1.为什么system_error

"....report error conditions originating from the operating system or low-level application program interfaces."

报告源于操作系统低层程序接口错误。 更进一步说,< system_error >提供了用于报告该方面错误的异常机制,是<stdexcept>的扩展

2.怎么用system_error

物以类聚,功能也以“类”分。 刚看到这个头文件的内容,我也有点懵逼,让我们先理清类与类之间的关系:

class-relations-image

虽然这几个类之间存在非常复杂的转换构造关系(实际上error_condition也可以通过error_category构造,但为了思路清晰,涂中没有给出),但我们记住一点----system_error是runtime_error的子类,是异常类。 因此在使用时,我们只要抓住system_error类就行了,构造并抛出

这里system_error主要有两种构造方法:

  • 借助error_code类构造
  • 借助error_condition类(通常通过errc枚举来构造)构造

这样一来我们的使用思路就很清晰了,都在图中,具体细节这里就不赘述了。

3.有趣的system_error

这里有个有趣的东西:

template <class T>
struct is_error_code_enum : public false_type {}

template <class T>
struct is_error_condition_enum : public false_type {}

从名字就能推测出,这两个结构体用来控制其他类型到error_code和error_condition类型的自动转换。 说到自动转换,肯定是通过类的conversion constructor进行的。

那么问题就来了,想要能进行类型转换,肯定得定义一个转换构造器;如果不想,就不能定义。 但这里只通过显示特化上面两个类,就能实现上述行为,这是怎么做到的呢? 这利用了模板函数 对重载决议的影响,也就是SFINAE(Substitute Error Is Not An Error)。

3.1 SFINA

下面举个例子:

template <class T>
struct MyType
{
};

template <>
struct MyType<double>
{
	typedef double type;
};

template <class T, class TT = typename MyType<T>::type>
void func(T t) { std::cout << "T" << std::endl; }

int main()
{
	int i;

	func(i);	//	ERROR!
	func(12.3);	//	OK!	
}

可以看到func模板函数有两个类型参数,以个为直接参数T,另一个为推导参数TT(为成员类型MyType< T >::type),这两个类型参数都需要在实例化时进行替换。 但是实际上我们只为MyType< double >类型定义了成员类型type,所以当函数func进行重载决议时发现MyType< int >类型没有成员类型type,无法对TT类型进行替换,因此签名为void func< int >(int t)的函数将会从重载函数集中去掉,结果就是不存在这样的重载函数, 上面的两个函数调用只有参数为double的能通过编译。

posted @ 2017-04-22 16:05  lgxZJ  阅读(5188)  评论(0编辑  收藏  举报