型が const 参照なのか識別する `is_const_referece<>` 的なもの

## ことの発端

```cpp
template <typename T> void foo(T&& v) {}
```

というテンプレート関数があった場合、`T` って色んな型を受け取ってくれるのですが、実際にどんか型が入ってくるのかを確認したく、テストコードを書いて見ました。

```cpp
#include <iostream>

template <typename T> void dump_attributes() {
  std::cout
    << "is_const=" << std::is_const<T>::value
    << ", is_reference=" << std::is_reference<T>::value
    << ", is_lvalue_reference=" << std::is_lvalue_reference<T>::value
    << ", is_rvalue_reference=" << std::is_rvalue_reference<T>::value
    << std::endl;
}

template <typename T> void foo(T&& v) {
  std::cout << "T -> ";
  dump_attributes<T>();
  std::cout << "v -> ";
  dump_attributes<decltype(v)>();
  std::cout << std::endl;
}

int main(void){

  const std::string a;
  std::string b;
  
  foo(a);
  foo(b);
  foo(std::move(b));
  foo(std::string());
  foo<std::string>("c");
}
```

すると、こんな結果になりまして。。。

```:結果
T -> is_const=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0
v -> is_const=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0

T -> is_const=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0
v -> is_const=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0

T -> is_const=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
v -> is_const=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1

T -> is_const=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
v -> is_const=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1

T -> is_const=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
v -> is_const=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1
```

まぁ、これはこれで、`右辺値` を渡しているところが、C++の仕様通り（当たり前です）で、これを実感できて「よしよし」なんて思ったんですが、`foo(a);`が何やらおかしい。
そう、`std::is_const<>` が false になっているんです。
で、`foo(a);` の `const` は何処に消えたのかと思って調べてみましたら、[cpprefjpの"std::is_const"の説明](https://cpprefjp.github.io/reference/type_traits/is_const.html) によりますと、「参照型は`const`修飾型ではない」と、備考に書いておりました。
ふむふむ。。。　ふぅ。。。（泣）
で、何故、このような仕様になったのかは調べても簡単には答えを探すことがでず今後の課題としますが、 `foo(a);` の場合、`std::is_const<>` が `const` じゃないと判定しても、実際に `v` に対して `非const` なオペレーションをするとコンパイルエラーになりますので、`v` は `const` であることには変わりません。

んじゃ、`is_const_reference<>` 的なの作れないかな？　って、ことになりました。

## 作ってみた

```cpp:is_const_reference
template <typename T> std::true_type  is_const_reference_func(const T&);
template <typename T> std::false_type is_const_reference_func(T&&);

template <typename T, typename U = decltype(is_const_reference_func(std::declval<T>()))>
struct is_const_reference : public U {};
```

参照以外は考慮していない簡単ポンな感じですが、まぁ、これで良しとしよう。。。
とりあえず、テストコードを書いてみて

```cpp
#include <iostream>
#include <utility>

template <typename T> std::true_type  is_const_reference_func(const T&);
template <typename T> std::false_type is_const_reference_func(T&&);

template <typename T, typename U = decltype(is_const_reference_func(std::declval<T>()))>
struct is_const_reference : public U {};

template <typename T> void dump_attributes() {
  std::cout
    << "is_const=" << std::is_const<T>::value
    << ", is_const_referece=" << is_const_reference<T>::value
    << ", is_reference=" << std::is_reference<T>::value
    << ", is_lvalue_reference=" << std::is_lvalue_reference<T>::value
    << ", is_rvalue_reference=" << std::is_rvalue_reference<T>::value
    << std::endl;
}

int main(){
  dump_attributes<std::string>();
  dump_attributes<const std::string>();
  dump_attributes<std::string&>();
  dump_attributes<const std::string&>();
  dump_attributes<std::string&&>();
}
```

```:結果
is_const=0, is_const_referece=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
is_const=1, is_const_referece=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0
is_const=0, is_const_referece=1, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0
is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1
```

良い感じ。。。

## 余談

表題の件は、ひとまず解決したので、「ことの発端」の結果をば。

```cpp
#include <iostream>
#include <utility>

template <typename T> std::true_type  is_const_reference_func(const T&);
template <typename T> std::false_type is_const_reference_func(T&&);

template <typename T, typename U = decltype(is_const_reference_func(std::declval<T>()))>
struct is_const_reference : public U {};

template <typename T> void dump_attributes() {
  std::cout
    << "is_const=" << std::is_const<T>::value
    << ", is_const_referece=" << is_const_reference<T>::value
    << ", is_reference=" << std::is_reference<T>::value
    << ", is_lvalue_reference=" << std::is_lvalue_reference<T>::value
    << ", is_rvalue_reference=" << std::is_rvalue_reference<T>::value
    << std::endl;
}

template <typename T> void foo(T&& v) {
  std::cout << "T -> ";
  dump_attributes<T>();
  std::cout << "v -> ";
  dump_attributes<decltype(v)>();
  std::cout << std::endl;
}

using namespace std;
int main(void){
  const std::string a;
  std::string b;
  
  foo(a);
  foo(b);
  foo(std::move(b));
  foo(std::string());
  foo<std::string>("c");
}
```

```:結果
T -> is_const=0, is_const_referece=1, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0
v -> is_const=0, is_const_referece=1, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0

T -> is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0
v -> is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=1, is_rvalue_reference=0

T -> is_const=0, is_const_referece=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
v -> is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1

T -> is_const=0, is_const_referece=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
v -> is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1

T -> is_const=0, is_const_referece=0, is_reference=0, is_lvalue_reference=0, is_rvalue_reference=0
v -> is_const=0, is_const_referece=0, is_reference=1, is_lvalue_reference=0, is_rvalue_reference=1
```

だから？って感じですが、`T&&` とした時に `T` がどんな型で、値がどんか型なのか実感できたので、満足満足。