Header <boost/type_traits.hpp>

<boost/type_traits.hpp>の内容はboost名前空間内で宣言される。

ファイル<boost/type_traits.hpp>は、型の基本的な特徴を説明する様々なテンプレートクラスを含んでいる。 各クラスは単一の型の特徴または単一の型の変形を意味する。本ライブラリに不慣れであれば、付随する記事を最初に読むこと。

このドキュメントは以下のセクションに分割される。

Primary Type Categorisation
Secondary Type Categorisation
Type Properties
Relationships Between Types
Transformations Between Types
Synthesizing Types
Function Traits
Compiler Support Information
Type traits headers
Example Code

本ライブラリにおける汎整数式はすべて汎整数定数式である。それらの使用は時折コンパイラの問題に遭遇する原因となるため, 本ライブラリを用いて移植性のあるコードを書くための手引きとしてコーディングガイドラインに関連した事項がある。

Primary Type Categorisation

以下の型特性(type traits)テンプレートは型がどの型分類に属しているかを識別する。どんな型を与えた場合でも、以下の式のうちのひとつは確実に真に評価される。 is_integral<T>::valueis_float<T>::valueは組み込み型についてのみ当てはまることに注意。あたかも汎整数型や浮動小数点型のように振舞うユーザ定義型を調べるのであれば、代わりにstd::numeric_limitsテンプレートを使うこと。

 

Expression

Description

Reference

Compiler requirements

 
  ::boost::is_void<T>::value Tがconst/volatile修飾されたvoid型であれば真に評価する。

3.9.1p9

   
  ::boost::is_integral<T>::value Tがconst/volatile修飾された汎整数型であれば真に評価する。

3.9.1p7

   
  ::boost::is_float<T>::value Tがconst/volatile修飾された浮動小数点型であれば真に評価する。

3.9.1p8

   
  ::boost::is_pointer<T>::value Tがconst/volatile修飾されたポインタ型であれば真に評価する(関数ポインタは含まれるが、メンバへのポインタは含まない)。

3.9.2p2

8.3.1

   
  ::boost::is_reference<T>::value Tが参照型であれば真に評価する。

3.9.2

8.3.2

   
  ::boost::is_member_pointer<T>::value Tがconst/volatile修飾されたデータメンバまたはメンバ関数へのポインタであれば真に評価する。

3.9.2

8.3.3

   
  ::boost::is_array<T>::value Tが配列型であれば真に評価する。

3.9.2

8.3.4

コンパイラがクラステンプレートの部分特殊化版をサポートしていない場合、型によっては間違って配列と認識されることがある(主に関数型)。  
  ::boost::is_union<T>::value Tが共用体型であれば真に評価する。現時点ではある種のコンパイラのサポートを必要とし、それ以外では共用体はクラスとして識別される。

3.9.2

9.5

C  
  ::boost::is_class<T>::value Tがクラス/構造体型であれば真に評価する。

3.9.2

9.2

C  
  ::boost::is_enum<T>::value Tが列挙型であれば真に評価する。

3.9.2

7.2

is_convertibleテンプレートが正しく機能することが必要(現時点ではis_enumがBorland C++では使えないという意味)。  
  ::boost::is_function<T>::value Tが関数型であれば真に評価する(関数への参照やポインタではない)。

3.9.2p1

8.3.5

部分特殊化版がサポートされない場合、このテンプレートは参照型についてはコンパイルできない。  

 

Secondary Type Categorisation

以下の型分類は1つ以上のprimary type categorisationsを組み合わせて作られている。ある型は、primary type categorisationsの分類に加えて、これらの分類のうちの1つ以上に属している可能性がある。

 

Expression

Description

Reference

Compiler requirements

 
  ::boost::is_arithmetic<T>::value Tがconst/volatile修飾された算術型であれば真に評価する。汎整数型か浮動小数点型のいずれかがこれにあたる。

3.9.1p8

   
  ::boost::is_fundamental<T>::value Tがconst/volatile修飾された基本型であれば真に評価する。汎整数型、浮動小数点型、void型のいずれかがこれにあたる。

3.9.1

   
  ::boost::is_object<T>::value Tがconst/volatile修飾されたオブジェクト型であれば真に評価する。関数型、参照型、void型以外がこれにあたる。

3.9p9

   
  ::boost::is_scalar<T>::value Tがconst/volatile修飾されたスカラ型であれば真に評価する。算術型、ポインタ型、メンバへのポインタ型がこれにあたる。

3.9p10

   
  ::boost::is_compound<T>::value Tが複合型であれば真に評価する。関数型、ポインタ型、参照型、列挙型、共用体型、クラス型、メンバ関数型がこれにあたる。

3.9.2

   
  ::boost::is_member_function_pointer<T>::value Tがメンバ関数へのポインタ型(メンバオブジェクトへのポインタではない)であれば真に評価する。このテンプレートはis_member_pointerを2つの副分類に分割する。

3.9.2

8.3.3

   

 

Type Properties

以下のテンプレートは型が持っている特徴を識別する。

 

Expression

Description

Reference

Compiler requirements

 
  ::boost::alignment_of<T>::value Tが必要とするアラインメントを識別する。実際に返される値は、Tが必要とする実際のアラインメントの倍数となることが保証される。      
  ::boost::is_empty<T>::value Tが空の構造体やクラスである場合に真。コンパイラが"空の基底クラスのサイズを0にする"最適化を実装しているのであれば、is_emptyはTが空であることを正しく推察する。 is_classがTがクラス型であることを判別できることが前提。

10p5

PCD

 
  ::boost::is_const<T>::value Tがトップレベルでconst修飾されている場合に真に評価する。

3.9.3

   
  ::boost::is_volatile<T>::value Tがvolatile修飾されていれば真に評価する。

3.9.3

   
  ::boost::is_POD<T>::value Tがconst/volatile修飾されたPOD型(訳註:Plane Old Data。非静的データメンバ、仮想関数、基本クラス、ユーザー定義コンストラクタ、コピーコンストラクタ、コピー代入演算子、およびデストラクタが含まれる)であれば真に評価する。

3.9p10

9p4

   
  ::boost::has_trivial_constructor<T>::value Tが自明なデフォルトコンストラクタを持っている、すなわちT()がmemsetと同等であれば真。  

PC

 
  ::boost::has_trivial_copy<T>::value Tが自明なコピーコンストラクタを持っている、すなわちT(const T&)がmemcpyと同等であれば真。  

PC

 
  ::boost::has_trivial_assign<T>::value Tが自明な代入演算子を持っている、すなわちT::operator=(const T&)がmemcpyと同等であれば真。  

PC

 
  ::boost::has_trivial_destructor<T>::value Tが自明なデストラクタを持っている、すなわちT::~T()が効果なしであれば真。  

PC

 
  ::boost::is_stateless<T>::value Tが実体を持たない、要するにTが記憶領域を持たず、コンストラクタとデストラクタがトリビアルであれば真。  

PC

 
  ::boost::has_nothrow_constructor<T>::value Tが例外を発生させないデフォルトコンストラクタを持っていれば真。   PC  
  ::boost::has_nothrow_copy<T>::value Tが例外を発生させないコピーコンストラクタを持っていれば真。   PC  
  ::boost::has_nothrow_assign<T>::value Tが例外を発生させない代入演算子を持っていれば真。   PC  

 

Relationships Between Types

以下のテンプレートは2つの型の間に関連性があるかどうかを調べる。

 

Expression

Description

Reference

Compiler requirements

 
 
::boost::is_same<T,U>::value

TとUが同じ型であれば真に評価する。

     
  ::boost::is_convertible<T,U>::value 型Tが型Uに変換できるのであれば真に評価する。

4

8.5

このテンプレートは、Borlandのコンパイラではコンストラクタベースの変換について、Metrowerksのコンパイラではすべての場合について、現時点では使用できないことに注意。  
  ::boost::is_base_and_derived<T,U>::value 型Tが型Uの基底クラスであれば真に評価する。 10 P  

is_convertibleおよびis_base_and_derivedでは、変換があいまいな場合にはコンパイラがエラーを出すので注意すること。

struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};
bool const x = boost::is_base_and_derived<A,D>::value;  // エラー
bool const y = boost::is_convertible<D*,A*>::value;     // エラー

Transformations Between Types

以下のテンプレートは、ある型を別の型に、いくつかの明確な規則に基づいて変形する。各テンプレートにはテンプレート引数Tを変形した結果であるtypeという名のメンバがひとつだけ含まれている。

 

Expression

Description

Reference

Compiler requirements

 
  ::boost::remove_const<T>::type Tと同じ型であるが、トップレベルのconst修飾子を取り除いた型を作る。例えば、"const int"は"int"になるが、"const int*"は変化しないままとなる。 3.9.3

P

 
  ::boost::remove_volatile<T>::type Tと同じ型であるが、トップレベルのvolatile修飾子を取り除いた型を作る。例えば、"volatile int"は"int"になる。

3.9.3

P

 
  ::boost::remove_cv<T>::type Tと同じ型であるが、トップレベルのconst/volatile修飾子を取り除いた型を作る。例えば、"const volatile int"は"int"になるが、"const int*"は変化せずそのままとなる。 3.9.3

P

 
  ::boost::remove_reference<T>::type Tが参照型であれば参照を取り除き、そうでなければTは変化せずそのままとなる。例えば、"int&"は"int"になるが、"int*"は変化しないままである。 8.3.2

P

 
  ::boost::remove_bounds<T>::type Tが配列型であればTからトップレベルの配列修飾子を取り除き、そうでなければTは変化せずそのままとなる。例えば、"int[2][3]"は"int[3]"になる。 8.3.4

P

 
  ::boost::remove_pointer<T>::type Tがポインタ型であればTから間接修飾を取り除き、そうでなければTは変化せずそのままとなる。例えば、"int*"は"int"になるが、"int&"は変化しないままである。 8.3.1

P

 
  ::boost::add_reference<T>::type Tが参照型であればTは変化せずそのままとなり、そうでなければTへの参照型に変換する。例えば、"int&"は変化せずにそのままであるが、"double"は"double&"になる。 8.3.2

P

 
  ::boost::add_pointer<T>::type "t"がTのインスタンスであるとき、add_pointer<T>::typeは"&t"が返す型である。例えば、"int"と"int&"はともに"int*"になる。 8.3.1

P

 
  ::boost::add_const<T>::type あらゆるTに対して"T const"と同じ。 3.9.3    
  ::boost::add_volatile<T>::type あらゆるTに対して"T volatile"と同じ。 3.9.3    
  ::boost::add_cv<T>::type あらゆるTに対して"T const volatile"と同じ。 3.9.3    

上記の表が示すように、型変形テンプレートを正しく実装するには部分特殊化版のサポートが必要である。一方で、経験上この分類に属するテンプレートの多くは非常に有益であり、ジェネリックライブラリの実装においてしばしば必須となる。 これらのテンプレートが不足していると、それらのライブラリを部分特殊化版の言語仕様をまだサポートしていないコンパイラに移植する上で大きな制約要因となる。 そうしたコンパイラの中にはしばらく部分特殊化版をサポートしないものがあり、少なくともそのうちの1つは非常に広く普及しているため、ライブラリでは移植を実現させるための回避手段を提供することにした。 回避手段を裏付ける基本的なアイデアは以下の通り。

  1. 全ての基本型と、それらから導かれる1段階および2段階のconst/volatile修飾された(または修飾されていない)全てポインタ型についての全型変形テンプレートの完全な特殊化版を手作業で定義する。そして、
  2. いかなるユーザ定義型 T に対してそうした明示的な特殊化版を定義できるようようにユーザレベルマクロを提供する。

最初の内容はこのようなものであり、コンパイルに成功することが保証されている。

BOOST_STATIC_ASSERT((is_same<char, remove_reference<char&>::type>::value));
BOOST_STATIC_ASSERT((is_same<char const, remove_reference<char const&>::type>::value));
BOOST_STATIC_ASSERT((is_same<char volatile, remove_reference<char volatile&>::type>::value));
BOOST_STATIC_ASSERT((is_same<char const volatile, remove_reference<char const volatile&>::type>::value));
BOOST_STATIC_ASSERT((is_same<char*, remove_reference<char*&>::type>::value));
BOOST_STATIC_ASSERT((is_same<char const*, remove_reference<char const*&>::type>::value));
...
BOOST_STATIC_ASSERT((is_same<char const volatile* const volatile* const volatile, remove_reference<char const volatile* const volatile* const volatile&>::type>::value));

そして次の内容は'char'、'int'や他の組み込み型だけでなく、独自に定義された型に対しても上記のコードを働かせるための仕組みをライブラリのユーザに提供する。

struct my {};
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(my)
BOOST_STATIC_ASSERT((is_same<my, remove_reference<my&>::type>::value));
BOOST_STATIC_ASSERT((is_same<my, remove_const<my const>::type>::value));
// etc.

部分特殊化版がサポートされないコンパイラでは、BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATIONは中身のないマクロとして評価されることに注意。

Synthesizing Types

以下のテンプレートは要求した特徴を持った型を作り出す。

 

Expression

Description

Reference

Compiler requirements

 
  ::boost::type_with_alignment<Align>::type Alignの倍数に整列された組み込み型またはPOD型を見つける。      

Function Traits

::boost::function_traitsクラステンプレートは関数型から情報を取り出す。
 

Expression

Description

Reference

Compiler requirements

 
  ::boost::function_traits<F>::arity 関数型Fの引数の数を調べる。   部分特殊化版がサポートされない場合、このテンプレートは参照型についてはコンパイルできない。  
  ::boost::function_traits<F>::result_type 関数型Fが返す型。   P  
  ::boost::function_traits<F>::argN_type 関数型Fの第N(1≦N≦Fの引数の数)引数の型。   P  

Compiler Support Information

上の表中にある記号の意味は以下の通り。

P

クラスが正しく働くためにはクラステンプレートの部分特殊化版のサポートを必要としていることを示す。

C

その特性クラスのためにコンパイラの直接的なサポートが必要であることを示す。

D

特性クラスがコンパイラの直接的なサポートを必要とするクラスに依存していることを示す。

 

DやCの印が付いたクラスに対して、コンパイラのサポートが受けられなければ、この型特性は実際には"真"が正しい場合に"偽"を返すことがある。この規則の唯一の例外は"is_class"で、Tが本当にクラスかどうかの推量を試みるにあたって、実際には"偽"が正しい場合に"真"を返すことがある。 こうしたことが起こるのは、Tが共用体あるいはコンパイラ独自のスカラ型(それらの型特性が特化されていない)の場合である。

コンパイラがサポートしていない場合、これらの特性が常に正しい値を返すことを保証するには、ユーザ定義のそれぞれの共用体型に対して'is_union'を、ユーザ定義のそれぞれの空の複合型に対して'is_empty'を、そしてユーザ定義のそれぞれのPOD型に対して'is_POD'を特化しなければならない。ユーザ定義型が'has_*'特性を持っておりPODではない場合には、'has_*'特性もまた特化すべきである。

以下の規則が自動的に当てはまる。

is_enumはis_PODでもある。

is_PODはhas_*でもある。

これが意味するのは、例えば、空のPOD構造体がある場合には、is_emptyとis_PODを特化し、すべてのhas_*が真を返すようにするということである。

Type Traits Headers

型特性ライブラリは通常下記をインクルードする。

#include <boost/type_traits.hpp>

とはいえ、ライブラリは実際にはいくつかのより小さいヘッダに分かれており、ときには実際に必要な型特性クラスを得るためにその中のひとつを直接インクルードする方が便利なことがある。しかし型特性クラスは相互依存性が高いことに注意すること。したがって、この方法は意外に節減にはならないかもしれない。以下の表では型特性クラスをアルファベット順に、各テンプレートが収められたヘッダとともに並べる。

  Template class Header  
  add_const <boost/type_traits/transform_traits.hpp>  
  add_const <boost/type_traits/transform_traits.hpp>  
  add_pointer <boost/type_traits/transform_traits.hpp>  
  add_reference <boost/type_traits/transform_traits.hpp>  
  add_volatile <boost/type_traits/transform_traits.hpp>  
  alignment_of <boost/type_traits/alignment_traits.hpp>  
  has_trivial_assign <boost/type_traits/object_traits.hpp>  
  function_traits <boost/type_traits/function_traits.hpp>  
  has_trivial_constructor <boost/type_traits/object_traits.hpp>  
  has_trivial_copy <boost/type_traits/object_traits.hpp>  
  has_trivial_destructor <boost/type_traits/object_traits.hpp>  
  is_arithmetic <boost/type_traits/arithmetic_traits.hpp>  
  is_array <boost/type_traits/composite_traits.hpp>  
  is_base_and_derived <boost/type_traits/object_traits.hpp>  
  is_class <boost/type_traits/object_traits.hpp>  
  is_compound <boost/type_traits/object_traits.hpp>  
  is_const <boost/type_traits/cv_traits.hpp>  
  is_convertible <boost/type_traits/conversion_traits.hpp>  
  is_empty <boost/type_traits/object_traits.hpp>  
  is_enum <boost/type_traits/composite_traits.hpp>  
  is_float <boost/type_traits/arithmetic_traits.hpp>  
  is_function <boost/type_traits/function_traits.hpp>  
  is_fundamental <boost/type_traits/arithmetic_traits.hpp>  
  is_integral <boost/type_traits/arithmetic_traits.hpp>  
  is_member_pointer <boost/type_traits/composite_traits.hpp>  
  is_member_function_pointer <boost/type_traits/composite_traits.hpp>  
  is_object <boost/type_traits/object_traits.hpp>  
  is_POD <boost/type_traits/object_traits.hpp>  
  is_pointer <boost/type_traits/composite_traits.hpp>  
  is_reference <boost/type_traits/composite_traits.hpp>  
  is_same <boost/type_traits/same_traits.hpp>  
  is_scalar <boost/type_traits/object_traits.hpp>  
  is_union <boost/type_traits/composite_traits.hpp>  
  is_void <boost/type_traits/arithmetic_traits.hpp>  
  is_volatile <boost/type_traits/cv_traits.hpp>  
  remove_bounds <boost/type_traits/transform_traits.hpp>  
  remove_const <boost/type_traits/cv_traits.hpp>  
  remove_cv <boost/type_traits/cv_traits.hpp>  
  remove_pointer <boost/type_traits/transform_traits.hpp>  
  remove_reference <boost/type_traits/transform_traits.hpp>  
  remove_volatile <boost/type_traits/cv_traits.hpp>  
  type_with_alignment <boost/type_traits/alignment_traits.hpp>  

 

Example code

型特性テンプレートを使用できるいくつかの方法を説明したプログラム例が4つある。

Copy_example.cpp

std::copyのコピー操作を最適化するために適宜memcpyを使用するバージョンを示す。

//
// opt::copy
// std::copyと同じセマンティクス
// 適宜memcpyを呼び出す。
//

namespace detail{

template<typename I1, typename I2>
I2 copy_imp(I1 first, I1 last, I2 out)
{
   while(first != last)
   {
      *out = *first;
      ++out;
      ++first;
   }
   return out;
}

template <bool b>
struct copier
{
   template<typename I1, typename I2>
   static I2 do_copy(I1 first, I1 last, I2 out)
   { return copy_imp(first, last, out); }
};

template <>
struct copier<true>
{
   template<typename I1, typename I2>
   static I2* do_copy(I1* first, I1* last, I2* out)
   {
      memcpy(out, first, (last-first)*sizeof(I2));
      return out+(last-first);
   }
};


}

template<typename I1, typename I2>
inline I2 copy(I1 first, I1 last, I2 out)
{
   typedef typename boost::remove_cv<typename std::iterator_traits<I1>::value_type>::type v1_t;
   typedef typename boost::remove_cv<typename std::iterator_traits<I2>::value_type>::type v2_t;
   return detail::copier<
      ::boost::type_traits::ice_and<
         ::boost::is_same<v1_t, v2_t>::value,
         ::boost::is_pointer<I1>::value,
         ::boost::is_pointer<I2>::value,
         ::boost::has_trivial_assign<v1_t>::value
      >::value>::do_copy(first, last, out);
}

fill_example.cpp

std::fillの充填操作を最適化するために適宜memsetを使用するバージョンを示す。 また、エイリアシング問題を避けるため、引数の受け渡しを最適化するためにcall_traitsを使用する。

namespace opt{
//
// fill
// std::fillと同じ。引数の受け渡しの"最適化"のために
// call_traitsとともに適宜memsetを使用する。
//
//
namespace detail{

template <typename I, typename T>
void do_fill_(I first, I last, typename boost::call_traits<T>::param_type val)
{
   while(first != last)
   {
      *first = val;
      ++first;
   }
}

template <bool opt>
struct filler
{
   template <typename I, typename T>
   struct rebind
   {
      static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val)
      { do_fill_<I,T>(first, last, val); }
   };
};

template <>
struct filler<true>
{
   template <typename I, typename T>
   struct rebind
   {
      static void do_fill(I first, I last, T val)
      {
         std::memset(first, val, last-first);
      }
   };
};

}

template <class I, class T>
inline void fill(I first, I last, const T& val)
{
   typedef detail::filler<
      ::boost::type_traits::ice_and<
         ::boost::is_pointer<I>::value,
         ::boost::is_arithmetic<T>::value,
         (sizeof(T) == 1)
      >::value> filler_t;
   typedef typename filler_t:: template rebind<I,T> binder;
   binder::do_fill(first, last, val);
}

};   // namespace opt

iter_swap_example.cpp

std::iter_swapの正規のものと同様の代替イテレータとともに動作するバージョンを示す。それは、正規のイテレータに対してstd::swapを呼び出すか、あるいは"遅いけれども安全"なswapを呼び出す。

namespace opt{
//
// iter_swap:
// イテレータが代替イテレータかどうかを調べ、
// それに応じて最適な形式を使う。
//
namespace detail{

template <bool b>
struct swapper
{
   template <typename I>
   static void do_swap(I one, I two)
   {
      typedef typename std::iterator_traits<I>::value_type v_t;
      v_t v = *one;
      *one = *two;
      *two = v;
   }
};

template <>
struct swapper<true>
{
   template <typename I>
   static void do_swap(I one, I two)
   {
      using std::swap;
      swap(*one, *two);
   }
};

}

template <typename I1, typename I2>
inline void iter_swap(I1 one, I2 two)
{
   typedef typename std::iterator_traits<I1>::reference r1_t;
   typedef typename std::iterator_traits<I2>::reference r2_t;
   detail::swapper<
      ::boost::type_traits::ice_and<
         ::boost::is_reference<r1_t>::value, 
         ::boost::is_reference<r2_t>::value,
         ::boost::is_same<r1_t, r2_t>::value
      >::value>::do_swap(one, two);
}

};   // namespace opt

Trivial_destructor_example.cpp

このアルゴリズムはstd::uninitialized_copyの逆である。初期化済みのメモリブロックを受け取り、その中のすべてのオブジェクトに対してデストラクタを呼び出す。これは一般には自分自身でメモリ管理を行うコンテナクラスの内部で使われる。

namespace opt{
//
// アルゴリズムdestroy_array:
// std::unitialized_copyの逆で、初期化済みのメモリブロックを受け取り、
// その中の全オブジェクトに対してデストラクタを呼び出す。
//

namespace detail{

template <bool>
struct array_destroyer
{
   template <class T>
   static void destroy_array(T* i, T* j){ do_destroy_array(i, j); }
};

template <>
struct array_destroyer<true>
{
   template <class T>
   static void destroy_array(T*, T*){}
};

template <class T>
void do_destroy_array(T* first, T* last)
{
   while(first != last)
   {
      first->~T();
      ++first;
   }
}

}; // namespace detail

template <class T>
inline void destroy_array(T* p1, T* p2)
{
   detail::array_destroyer<boost::has_trivial_destructor<T>::value>::destroy_array(p1, p2);
}
} // namespace opt

Revised 22 April 2001

Documentation © Copyright John Maddock 2001. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.

The type traits library is based on contributions by Steve Cleary, Beman Dawes, Aleksey Gurtovoy, Howard Hinnant, Jesse Jones, Mat Marcus, John Maddock and Jeremy Siek.

Mat Marcus and Jesse Jones have worked on, and published a paper describing the partial specialisation workarounds used in this library.

The is_convertible template is based on code originally devised by Andrei Alexandrescu, see "Generic<Programming>: Mappings between Types and Values".

Maintained by John Maddock, the latest version of this file can be found at www.boost.org, and the boost discussion list at www.yahoogroups.com/list/boost.

Japanese Translation Copyright © 2003 Takagi,Yusei
オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」に提供されており、いかなる明示的、暗黙的保証も行わない。また、いかなる目的に対しても、その利用が適していることを関知しない。