Skip to content

Instantly share code, notes, and snippets.

@t-mat
Created September 9, 2012 10:43
Show Gist options
  • Save t-mat/3683729 to your computer and use it in GitHub Desktop.
Save t-mat/3683729 to your computer and use it in GitHub Desktop.
ポインタの指す先を `decltype` したい

ポインタの指す先を decltype したい

まとめ

Wikipedia の decltype についての記事を見るのがいいよ!

  • T へのポインタ T* p が指す先を decltype(*p) と書くと T& となる
  • T への const ポインタ const T* p が指す先を decltype(*p) と書くと const T& となる
  • T& から参照を外すには std::remove_reference<> を使う
  • const T から const を外すには std::remove_const<> を使う
  • T* ポインタを外すには std::remove_pointer<> を使う

のだと思う。たぶん。

順番に見ていく

以下のようなコードがあるとき

#include <stdio.h>
#include <string.h>
int main() {
  const char* p = "TEST";
  char b[256];
  return puts(strcpy(b, p));
}
// TEST

p が指す型に合わせて b の型も変わって欲しい、でもテンプレート関数は嫌」 という場合に decltype を使って

// ERROR
#include <stdio.h>
#include <string.h>
int main() {
  const char* p = "TEST";
  decltype(*p) b[256];
  return puts(strcpy(b, p));
}
// ERROR

などと書きたいが、これはエラーになる。

エラーでは参照が云々とか言われるがよく分からないので、 以下のコードで decltype(*p) の型が何なのかを見てみると

#include <type_traits>
#include <stdio.h>
int main() {
  const char* p = "TEST";
  printf("%d, %d, %d, %d\n"
    , std::is_same<const char&, decltype(*p)>::value
    , std::is_same<const char , decltype(*p)>::value
    , std::is_same<      char&, decltype(*p)>::value
    , std::is_same<      char , decltype(*p)>::value
  );
  return 0;
}
// 1, 0, 0, 0

となるので、decltype(*p)const char& だということが分かった。 そこで &const をはずすことを目標にする。

まず、& をはずすには std::remove_reference<> を使う

#include <type_traits>
#include <stdio.h>
int main() {
  const char* p = "TEST";
  printf("%d, %d, %d, %d\n"
    , std::is_same<const char&, std::remove_reference<decltype(*p)>::type>::value
    , std::is_same<const char , std::remove_reference<decltype(*p)>::type>::value
    , std::is_same<      char&, std::remove_reference<decltype(*p)>::type>::value
    , std::is_same<      char , std::remove_reference<decltype(*p)>::type>::value
  );
  return 0;
}
// 0, 1, 0, 0

次に、const をはずすには std::remove_const<> を使う

#include <type_traits>
#include <stdio.h>
int main() {
  const char* p = "TEST";
  printf("%d, %d, %d, %d\n"
    , std::is_same<const char&, std::remove_const<std::remove_reference<decltype(*p)>::type>::type>::value
    , std::is_same<const char , std::remove_const<std::remove_reference<decltype(*p)>::type>::type>::value
    , std::is_same<      char&, std::remove_const<std::remove_reference<decltype(*p)>::type>::type>::value
    , std::is_same<      char , std::remove_const<std::remove_reference<decltype(*p)>::type>::type>::value
  );
  return 0;
}
// 0, 0, 0, 1

この結果をもとにして、以下のように書くことで目的は果たせた

#include <type_traits>
#include <stdio.h>
#include <string.h>
int main() {
  const char* p = "TEST";
  std::remove_const<std::remove_reference<decltype(*p)>::type>::type b[256];
  return puts(strcpy(b, p));
}
// TEST

不細工だなー

std::remove_pointer<>はどうだろう?

p に対して直接 std::remove_pointer<> 使うのではなく、 decltype を付けてから使う

#include <type_traits>
#include <stdio.h>
int main() {
  const char* p = "TEST";
  printf("%d, %d, %d, %d\n"
    , std::is_same<const char&, std::remove_pointer<decltype(p)>::type>::value
    , std::is_same<const char , std::remove_pointer<decltype(p)>::type>::value
    , std::is_same<      char&, std::remove_pointer<decltype(p)>::type>::value
    , std::is_same<      char , std::remove_pointer<decltype(p)>::type>::value
  );
  return 0;
}
// 0, 1, 0, 0

あとは std::remove_const<> を使って const を外す

#include <type_traits>
#include <stdio.h>
int main() {
  const char* p = "TEST";
  printf("%d, %d, %d, %d\n"
    , std::is_same<const char&, std::remove_const<std::remove_pointer<decltype(p)>::type>::type>::value
    , std::is_same<const char , std::remove_const<std::remove_pointer<decltype(p)>::type>::type>::value
    , std::is_same<      char&, std::remove_const<std::remove_pointer<decltype(p)>::type>::type>::value
    , std::is_same<      char , std::remove_const<std::remove_pointer<decltype(p)>::type>::type>::value
  );
  return 0;
}
// 0, 0, 0, 1

最終的には以下のようになった

#include <type_traits>
#include <stdio.h>
#include <string.h>
int main() {
  const char* p = "TEST";
  std::remove_const<std::remove_pointer<decltype(p)>::type>::type b[256];
  return puts(strcpy(b, p));
}
// TEST

あんまり変わらなかった。残念

autoだとどうなるの?

auto のルールから、ポインタの指す先を auto で受け取ると、そのまま値となる

#include <type_traits>
#include <stdio.h>
int main() {
  const char* p = "TEST";
  auto c = *p;
  printf("%d, %d, %d, %d\n"
    , std::is_same<const char&, decltype(c)>::value
    , std::is_same<const char , decltype(c)>::value
    , std::is_same<      char&, decltype(c)>::value
    , std::is_same<      char , decltype(c)>::value
  );
  return 0;
}
// 0, 0, 0, 1

ので受け取った auto の変数を decltype に使うことができる

// ???
#include <type_traits>
#include <stdio.h>
#include <string.h>
int main() {
  const char* p = "TEST";
  auto c = *p;
  decltype(c) b[256];
  return puts(strcpy(b, p));
}
// TEST
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment