メンバ関数の存在を調べるテンプレートメタ関数を量産する

# 目標に対して妥協点まではきた気がする

僕よりも優れた先人のサンプルコード

* [C++テンプレートテクニック 第2版](https://www.amazon.co.jp/dp/B00QJINRYI/)
* [C++メタ関数のまとめ](https://qiita.com/_EnumHack/items/ee2141ad47915c55d9cb)
* [【再考】メンバの存在を調べる](https://qiita.com/z0ero/items/3f104eb42ad3fa69b777)

を参考に、

* メンバ関数の有無のみを確認する
* メンバ変数は除外
* いろいろな引数の関数に対応する

を量産するマクロを作成してみました。
変数を除外したのは、変数と関数を区別したかったためです。

妥協点までいったような、というコード全容はこちらです。

```cpp

#include <iostream>
#include <vector>

namespace has_member_function { 

#define HAS_MEMBER_FUNCTION( FunctionName, UniqueID, ... ) \
template < typename T > \
class FunctionName ## UniqueID { \
\
  template< typename Arg > \
  static auto impl( ... ) -> std :: false_type; \
\
  template < typename Arg > \
  static auto impl( Arg* ) -> \
  decltype( \
      std :: declval < Arg >() . FunctionName( __VA_ARGS__ ) \
    , std :: true_type() \
  ); \
\
  public: \
    static constexpr bool value = decltype( impl< T >(nullptr) ) :: value ; \
};

HAS_MEMBER_FUNCTION( size,,  ); // check is T.size()  exist
HAS_MEMBER_FUNCTION( begin,, ); // check is T.begin() exist
HAS_MEMBER_FUNCTION( end,,   ); // check is T.end()   exist
HAS_MEMBER_FUNCTION( empty,, ); // check is T.empty() exist

}

void print( const bool value ){ 
  std :: cout << std :: boolalpha << value << std :: endl;
}

struct A {  };
struct B {  };
struct C {  
  void fx ( const A&, const B& );
};

struct D {
    int func;
};

namespace has_member_function{ 
  HAS_MEMBER_FUNCTION( at, , 0 );
  HAS_MEMBER_FUNCTION( fx, void, );
  HAS_MEMBER_FUNCTION( fx, A_B, A(), B() );
}

int main()
{

    
  print( has_member_function :: size < std :: vector< int > > :: value );
  print( has_member_function :: begin< std :: vector< int > > :: value );
  print( has_member_function :: end  < std :: vector< int > > :: value );
  print( has_member_function :: empty< std :: vector< int > > :: value );

  print( has_member_function :: at   < std :: vector< int > > :: value );

  print( has_member_function :: fxA_B < C > :: value );
    
  print( has_member_function :: fxvoid < D > :: value );
    
  return 0;
}
```

## ざっくりマクロ解説

例えば

```cpp
namespace has_member_function{
 HAS_MEMBER_FUNCTION(size, , );
}
```

は

```cpp
namespace has_member_function {
template < typename T > 
class size {

  template< typename Arg >
  static auto impl( ... ) -> std :: false_type;

  template < typename Arg >
  static auto impl( Arg* ) ->
  decltype(
      std :: declval < Arg >() . size( )
    , std :: true_type()
  );
  public: 
    static constexpr bool value = decltype( impl< T >(nullptr) ) :: value ;
};
}
```

と展開され、 `size()` の有無を確認したいクラス `C` に対して

```cpp
has_member_function :: size<C> :: value
```
と利用することができます。

## マクロの詳細

作成したマクロは

`HAS_MEMBER_FUNCTION(FunctionName, UniqueID, ...)`

と2つ以上の引数をとります。

#### `FunctionName`
確認したいメンバ関数名です。同時に生成するクラス名の一部になります。

#### `UniqueID`
オーバーロード等、同名のメンバ関数を区別するための識別子として利用します。

* 検証するクラス `C`
* 検証するメンバ関数 `test_func()` 
* 生成する際のマクロ`HAS_MEMBER_FUNCTION(test_func, 01, )` 

とした場合、生成されるメタ関数、及びそれを利用する方法は

```cpp
test_func01<C> :: value // check C :: test_func() 
```

となります。

#### `...`

検証するメンバ関数の引数を `UniqueID` 以降に記述します。
サンプルコードでは

```cpp
  HAS_MEMBER_FUNCTION( at, , 0 );           // example -> std :: vector<...>.at(...)
  HAS_MEMBER_FUNCTION( fx, A_B, A(), B() ); // example -> check C.fx(...)
```

このように利用しています。



ここまでの変数を用いてメンバ関数を検証しているのは

```cpp
  decltype( \
      std :: declval < Arg >() . FunctionName( __VA_ARGS__ ) \ //<- Here
    , std :: true_type() \
  ); \
```

この部分になります。`fx(const A&, const B&)` メンバ関数を検証するメタ関数を `HAS_MEMBER_FUNCTION( fx, A_B, A(), B() );`
で生成すると、各引数が展開され

```cpp
  decltype(
      std :: declval < Arg >().fx( A(), B() ) //<- Here
    , std :: true_type()
  );
```

と変化します。

## 動作サンプルと実行結果

`std :: vector<int>` 型や自作の型をサンプルにメンバ関数の検証をしました。

検証用メタ関数生成

```cpp
namespace has_member_function {
  HAS_MEMBER_FUNCTION( size,,  ); // check is T.size()  exist
  HAS_MEMBER_FUNCTION( begin,, ); // check is T.begin() exist
  HAS_MEMBER_FUNCTION( end,,   ); // check is T.end()   exist
　HAS_MEMBER_FUNCTION( empty,, ); // check is T.empty() exist
}

namespace has_member_function{ 
  HAS_MEMBER_FUNCTION( at, , 0 );
  HAS_MEMBER_FUNCTION( fx, void, );
  HAS_MEMBER_FUNCTION( fx, A_B, A(), B() );
}
```


検証用クラス宣言

```cpp
struct A {  };
struct B {  };
struct C {  
  void fx ( const A&, const B& );
};

struct D {
    int func;
};
```

プリントデバッグ用関数

```cpp
void print( const bool value ){ 
  std :: cout << std :: boolalpha << value << std :: endl;
}
```

`main`関数

```cpp
int main()
{
  print( has_member_function :: size < std :: vector< int > > :: value );
  print( has_member_function :: begin< std :: vector< int > > :: value );
  print( has_member_function :: end  < std :: vector< int > > :: value );
  print( has_member_function :: empty< std :: vector< int > > :: value );

  print( has_member_function :: at   < std :: vector< int > > :: value );

  print( has_member_function :: fxA_B < C > :: value );

  print( has_member_function :: fxvoid < D > :: value );

  return 0;
}
```

実行結果

```
Start

true
true
true
true
true
true
false

0

Finish
```

https://wandbox.org/permlink/uR2MZD8b8IigkhKI

## ここまでの右往左往

`std :: function` に代入できるかで判定するというのも考えました。が、
`std :: vector<...>.at(...)` の引数とか戻り値とかを調べたり記述したりするとすごく冗長になってしまう気がしたので頓挫しました。
// でも `at` の引数に `0` 渡して確認ってうーーーーん。

メンバに対するアドレスを取得する方法だとメンバ変数も入ってしまうのでこれも除外しました。

8/16 2:16 JST

あ、`std :: is_function` ...
でも引数の型を比べれないのか。

## 終わりに

もっとスマートな方法、もっとクレイジーな方法あると思いますので、思いついたら方はコメントであるとか記事を作っていただけたらと思います。

<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="クリエイティブ・コモンズ・ライセンス" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a>