boost BOOST_IDENTITY_TYPE

目录

动机

解决方案

模板

抽象类型

用法

实现

用户手册

此库允许用圆括号包装类型,使这些类型可以直接当作宏参数传递

动机

考虑实现用类型type定义一个变量varn 功能宏:

#define VAR(type, n) type var ## n
VAR(int, 1);                    // OK.
VAR(std::map<int, char>, 2);    // Error.

第一个宏调用可以正常的定义一个int类型的var1变量,但是第二个宏调用会产生一个类似如下信息的预编译错误:

error: macro "VAR" passed 3 arguments, but takes just 2

这是由于当作宏参数传递的std::map类型中有没有被圆括号()包装的逗号。预处理器认为没有被圆括号包装的逗号是宏参数的分隔符,所以它认为总共有3个(而不是2个)参数按如下顺序调用了宏:

std::map<int

char>

2

请注意,对于不同的编译器,预处理器只能识别圆括号()。尖括号<>和方括号[]在解析宏参数的时候都不能被预处理器识别。

解决方案

在某些情况下,可以通过避免直接用类型调用宏来解决这个问题。例如,可以用typedef重定义原来的类型表达式:

typedef std::map<int, char> map_type;
VAR(map_type, 3); // OK.

当不希望或者不太可能这样的时候,头文件boost/utility/identity_type.hpp中定义了一个BOOST_IDENTITY_TYPE宏来解决这个问题,这个宏保证了类型表达式是宏的一个参数。

#include <boost/utility/identity_type.hpp>
VAR(BOOST_IDENTITY_TYPE((std::map<int, char>)), 4); // OK.

BOOST_IDENTITY_TYPE宏被扩展成了一个在编译时计算指定类型的表达式。指定类型没有被分割多个宏参数,因为它总是被一对额外的圆括号()包装起来。事实上,总共使用了2对圆括号:调用BOOST_IDENTITY_TYPE(...) 宏的圆括号,和包装传递进BOOST_IDENTITY_TYPE((...))宏的类型参数的内部圆括号。

此宏对任何支持的C++03 编译器都有效(它没有使用变长参数宏)。

模板

This macro must be prefixed by typename when used within templates. For example, let's program a macro that declares a function parameter named with the specified type (see also template.cpp):

当和模板一起使用的时候,必须在宏调用的前面加上typename。例如,实现一个定义一个类型为type的变量argn 功能的宏:

#define ARG(type, n) type arg ## n
template<typename T>
void f( // Prefix macro with `typename` in templates.
    	ARG(typename BOOST_IDENTITY_TYPE((std::map<int, T>)), 1)
) {
    	 std::cout << arg1[0] << std::endl;
}
std::map<int, char> a;
a[0] = 'a';
 
f<char>(a); // OK...
// f(a);    // ... but error.

值得注意的是,模板参数char必须在函数调用的时候显式指定,如f<char>(a)事实上,当用BOOST_IDENTITY_TYPE宏包装函数模板参数的时候,模板参数在函数调用f(a)不能被编译器自动推导出来(类模板没有这个限制,因为类模板参数总是必须被显式指定)。也就是说,如果不使用BOOST_IDENTITY_TYPE宏,C++编译器一般都能自动的推导出函数模板参数:

template<typename T>
void g(std::map<int, T> arg1) 
{
    	 std::cout << arg1[0] << std::endl;
}
g<char>(a); // OK...
g(a);       // ... and also OK.

抽象类型

当用抽象类型(有一个以上纯虚函数的类)调用BOOST_IDENTITY_TYPE宏时,一些编译器(比如GCC)会报错。这个问题可以通过对类型增加和移除引用操作来解决。

比如实现一个Template Meta-Programming (TMP) 元函数静态断言的宏(和Boost.MPLBOOST_MPL_ASSERT类似)。BOOST_IDENTITY_TYPE宏可以用来将多模板参数的元函数传进断言宏。在这种情况下,如果元函数是一个抽象类型,则它需要对类型进行增加或移除引用操作。

#define TMP_ASSERT(metafunction) \
    	 BOOST_STATIC_ASSERT(metafunction::value)
template<typename T, bool b>
struct abstract {
    	 static const bool value = b;
    	 virtual void f(T const& x) = 0;     // Pure virtual function.
};
TMP_ASSERT(
    	 boost::remove_reference<            // Add and remove
        	 BOOST_IDENTITY_TYPE((           // reference for
            	 boost::add_reference<       // abstract type.
                	 abstract<int, true>
            	 >::type
        	 ))
    	 >::type
);

使用

BOOST_IDENTITY_TYPE宏既可以在调用用户自定义宏时使用,也可以在用户自定义宏实现里面调用(正如下面的例子)。当在用户自定义宏实现中使用BOOST_IDENTITY_TYPE宏时,用户自定义宏调用者必须指定额外的圆括号:

#define TMP_ASSERT_PAREN(parenthesized_metafunction) \
    	 /* use `BOOST_IDENTITY_TYPE` in macro definition instead of invocation */ \
    	 BOOST_STATIC_ASSERT(BOOST_IDENTITY_TYPE(parenthesized_metafunction)::value)
 
#define TMP_ASSERT(metafunction) \
    	 BOOST_STATIC_ASSERT(metafunction::value)
 
// Specify only extra parenthesis `((...))`.
TMP_ASSERT_PAREN((boost::is_const<std::map<int, char> const>));
 
// Specify both the extra parenthesis `((...))` and `BOOST_IDENTITY_TYPE` macro.
TMP_ASSERT(BOOST_IDENTITY_TYPE((boost::is_const<std::map<int, char> const>)));

值得注意的是,即使这里宏参数中并没有包含逗号,调用者都必须指定额外的圆括号:

TMP_ASSERT_PAREN((boost::is_const<int const>)); // Always extra `((...))`.
TMP_ASSERT(boost::is_const<int const>); // No extra `((...))` and no macro.

实现

BOOST_IDENTITY_TYPE宏实现如下:

#include <boost/type_traits/function_traits.hpp>
 
#define BOOST_IDENTITY_TYPE(parenthesized_type) \
    	 boost::function_traits<void parenthesized_type>::arg1_type

类型必须被圆括号包装(std::map<int, char>),这样之后,即使类型中有逗号,它也会能被当作单个宏参数。之后,括起来的类型转换成一个返回void并且带有唯一指定参数的函数类型void (std::map<int, char>)。最终,第一参数arg1_type类型在编译时被function_traits元函数抽取出来。因此就获取到了原来被括号括起来的类型。

用户手册

头文件<boost/utility/identity_type.hpp>

用圆括号包装类型表达式,使得类型表达式中即使有逗号也能当作宏参数传递。

BOOST_IDENTITY_TYPE(parenthesized_type)

BOOST_IDENTITY_TYPE

BOOST_IDENTITY_TYPE — This macro allows to wrap the specified type expression within extra round parenthesis so the type can be passed as a single macro parameter even if it contains commas (not already wrapped within round parenthesis).

摘要

// In header: <boost/utility/identity_type.hpp>

BOOST_IDENTITY_TYPE(parenthesized_type)

描述

参数:

parenthesized_type

可以作为宏参数传递并且被一对圆括号包装的类型表达式,它可以包含任意多个逗号。

此宏对任何支持的C++03 编译器都有效(它没有使用变长参数宏)。

此宏在和模板一起使用的时候必须在前面加上typename。值得注意的是,当用此宏包装模板参数时,编译器不能自动推导出函数模板参数(模板参数必须在调用函数模板时显式指定)。

当用抽象类型调用此宏时,一些编译器(比如GCC)需要在指定类型上增加或移除引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值