Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Other considerations and tips(其它考慮和提示)

Native typeof support and emulation(原生 typeof 支持及仿真)
The three participating parties(三個參與方)
Supported features(支持的特性)
What needs to be registered?(需要註冊什麼?)
Limitations(限制)

Native typeof support and emulation(原生 typeof 支持及仿真)

很多編譯器已經支持了 typeof,最值得關注的是 GCC 和 Metrowerks。

Igor Chesnokov 發現一個允許在 VC 系列編輯器上實現 typeof 的方法。它利用了微軟編譯器的一個 bug,這個 bug 允許一個基類的內嵌類定義在從基類派生出的類中:

template<int ID> struct typeof_access
{
    struct id2type; //not defined
};

template<class T, int ID> struct typeof_register : typeof_access
{
    // define base's nested class here
    struct typeof_access::id2type
    {
        typedef T type;
    };
};

//Type registration function 
typeof_register<T, compile-time-constant> register_type(const T&);

//Actually register type by instantiating typeof_register for the correct type
sizeof(register_type(some-type)); 

//Use the base class to access the type.
typedef typeof_access::id2type::type type; 

當內嵌類是一個在派生類中特化的模板類時,這個方法也適合於 VC7.0。不過,這個漏洞在 VC8.0 中被修復,因此在這個編譯器上這個方法不能工作。

VC8.0 和許多其它編譯器既沒有原生 typeof 支持,也沒有像上面描述的訣竅作為一種選擇。對於這樣的編譯器仿真方法就是實現 typeof 的唯一出路。

根據一個大體的預測,在寫這篇文章的時候,typeofauto 等被引入 C++ 標準的事情可能還不會馬上發生。即使在那之後,依然需要一段時間,大多數編譯器才能實現這個特性。但是即使在那之後,總還有一些老舊的編譯器需要支持(例如,現在,2005 年,VC7.x 出現很長時間了,甚至 VC8.0 beta 已經可以使用了,很多人依然使用 VC6)。

要想立刻使用這個非常有用的特性,把它實現在庫的層次顯然是很合理的。

仿真方式顯然很重要,即使在一些特定編譯器上提供了更好的選擇。如果一個庫作者想要使用 typeof 開發可移植代碼,她需要使用仿真方式並註冊她的類型和模板。那些仿真是唯一選擇的用戶可以使用它,而那些有著更好選擇的用戶也依然可以使用它,因為在這樣的編譯器上註冊宏被定義為 no-op(什麼都不做)。

還有一些其它考慮適用於 VC7.1 的用戶。即使有更方便的 typeof 訣竅可用,也應該考慮到升級到 VC8 的可能性,在那個編譯器上仿真是唯一的選擇。

通過定義 BOOST_TYPEOF_COMPLIANT 符號,可以將仿真模式強加於那些缺省時不使用它的編譯器:

g++ -D BOOST_TYPEOF_COMPLIANT -I \boost\boost_1_32_0 main.cpp

The three participating parties

動機部分的 Lambda 示例需要如下註冊:

#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
 
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::tuples::tuple, 2);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::lambda_functor, 1);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::lambda_functor_base, 2);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::relational_action, 1);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::logical_action, 1);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::other_action, 1);
BOOST_TYPEOF_REGISTER_TYPE(boost::lambda::greater_action);
BOOST_TYPEOF_REGISTER_TYPE(boost::lambda::less_action);
BOOST_TYPEOF_REGISTER_TYPE(boost::lambda::and_action);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::placeholder, (int));

看上去,為了具有發現表達式的類型的能力所付出的代價太高了:需要相當大量的註冊。然而請注意,上面所有這些註冊只需要做一次,在那之後,已註冊類型和模板的任意組合都可以被處理。此外,這些註冊一般不需要最終用戶的參與,而是由一些庫的建構者來做(在本例中是 Boost.Lambda)。

在考慮這些的時候,考慮一下參與的三方是有幫助的:typeof 設施,庫(很可能基於表達式模板法則),和最終用戶。typeof 設施負責註冊基本類型。庫可以註冊它自己的類型和模板。

在最理想的狀態下,如果表達式總是由基本類型和庫定義的類型與模板組成,一個庫的作者可能會覺得 typeof 是被它的庫原生支持的。另一方面,表達式越經常地包含用戶定義類型,就有越多的責任落在最終用戶身上,並由此這個方法就變得越不吸引人。

這樣一來,當決定是否要應用 typeof 設施時,表達式中用戶定義類型的比例成為要考慮的主要因素。

Supported features(支持的特性)

Typeof 預先註冊了基本類型。對於這些類型,以及由用戶庫和最終用戶註冊的任何類型/模板,與以下的任意組合都已被支持:

  • 指針;
  • 引用(頂層除外);
  • Consts(頂層除外);
  • Volatiles(頂層除外);
  • 數組;
  • 函數,函數指針,及引用;
  • 指向成員函數的指針;
  • 指向數據成員的指針。

例如,下面的類型:

int& (*)(const volatile char*, double[5], void(*)(short))

被毫無疑問地支持,而下面這樣的:

void (MyClass::*)(int MyClass::*, MyClass[10]) const

如果 MyClass 被註冊,即可被支持。

Typeof 庫為大多數 STL 類/模板提供了註冊文件。這些文件位於 std 子目錄內,命名與相應的 STL 頭文件相同。這些文件沒有被 typeof 系統包含,必須由用戶根據需要顯式包含:

#include <boost/typeof/std/functional.hpp>
BOOST_AUTO(fun, std::bind2nd(std::less<int>(), 21)); //create named function object for future use.

What needs to be registered?(需要註冊什麼?)

為 Typeof 庫註冊類型的時候利用編譯器是可能的。即使當前還沒有在語言中直接支持 typeof,如果編譯器遇到無法正確處理的表達式,它可以覺察到表達式的類型是什麼並給出錯誤信息。在 typeof 上下文中,這個錯誤信息包含的線索能給你一些啟發,告訴你為了使 BOOST_TYPEOF 可以工作,需要為 Typeof 庫註冊什麼類型。

struct X {};
 
template<typename A,bool B>
struct Y {};

std::pair<X,Y<int,true> > a;

BOOST_AUTO(a,b);

我們從 VC7.1 得到如下錯誤信息

error C2504: 'boost::type_of::'anonymous-namespace'::encode_type_impl<V,Type_Not_Registered_With_Typeof_System>' : base
    class undefined
        with 
        [
            V=boost::type_of::'anonymous-namespace'::encode_type_impl<boost::mpl::vector0<boost::mpl::na>,std::pair<X,Y<int,true>>>::V0,
            Type_Not_Registered_With_Typeof_System=X
        ]

檢查這個錯誤信息,我們看到編譯器在抱怨 X

BOOST_TYPEOF_REGISTER_TYPE(X); //register X with the typeof system

再編譯,我們從 VC7.1 得到一個新的錯誤信息

error C2504: 'boost::type_of::'anonymous-namespace'::encode_type_impl<V,Type_Not_Registered_With_Typeof_System>' : base
    class undefined
        with
        [
            V=boost::type_of::'anonymous-namespace'::encode_type_impl<boost::mpl::vector0<boost::mpl::na>,std::pair<X,Y<int,true>>>::V1,
            Type_Not_Registered_With_Typeof_System=Y<int,true>
        ]

檢查這個錯誤信息,我們看到編譯器在抱怨 Y<int,true>。因為 Y 是一個模板,並且包含整型常量,註冊時我們需要更加小心:

BOOST_TYPEOF_REGISTER_TEMPLATE(Y,(typename)(bool)); //register template class Y

Y 包含整型常量時,查尋它的精確定義是個好主意。對於只包含 typenames 的簡單模板類,你可以完全依賴編譯器錯誤。

上面的代碼現在可以編譯了。

這一技術可以用於得到一個「為了讓一個給定的項目支持 typeof,有哪些類型需要被註冊」的概覽。

Limitations(限制)

不支持嵌套的 template template parameters(模板模板參數),比如:

template<template<template<class> class> class Tpl> 
class A; // can't register!

嵌套在其它模板中的類和模板也由於 nondeduced context(非推演上下文)的問題而不能註冊。這一限制在涉及到 Dinkumware STL 的標準迭代器時最應該引起注意,它們被實現為嵌套類。作為替代,它們的實例是可以被註冊的:

BOOST_TYPEOF_REGISTER_TYPE(std::list<int>::const_iterator)
Copyright 2004, 2005 Arkadiy Vertleyb, Peder Holt

PrevUpHomeNext