effective modern c++ 勉強会#1 item3,4

24
Effective Modern C++ 勉強会#1 Item 3, 4 星野 喬 (@starpoz) サイボウズ・ラボ 2015-01-28 1

Upload: takashi-hoshino

Post on 17-Jul-2015

716 views

Category:

Technology


3 download

TRANSCRIPT

Effective Modern C++勉強会#1 Item 3, 4

星野喬 (@starpoz)

サイボウズ・ラボ

2015-01-28

1

Item 3Understand decltype.

2

decltypeの基本的なルール

• decltypeは通常、名前や式で与えたものの型を返す

3

const int i = 0; // decltype(i) is const int.

bool f(const Widget& w); // decltype(w) is const Widget&,

// decltype(f) is

// bool(const Widget&)

struct Point {int x, y;}; // decltype(Point::x) is int.

Widget w; // decltype(w) is Widget.

f(w); // decltype(f(w)) is bool.

コンテナのoperator[]が返す型

•コンテナのoperator[]は通常T&を返すが、std::vector<bool>はbool&を返さない

4

template <typename T>

struct my_vector {

T& operator[](size_t i);

};

my_vector<int>v; // decltype(v) is my_vector<int>.

v[0]; // decltype(v[0]) is int&.

std::vector<bool> w; // decltype(w) is std::vector<bool>.

w[0]; // decltype(w[0]) is

// std::_Bit_reference&.

// (using clang++)

operator[]の返す型を返す関数

• C++11:単文ラムダのみ返り値の型を推論

• C++14:任意のラムダ、関数で推論

5

// C++11

template <typename Container, typename Index>

auto authAndAccess(Container& c, Index i) -> decltype(c[i])

{

return c[i];

}

// C++14

template <typename Container, typename Index>

auto authAndAccess(Container& c, Index i) {

return c[i];

} これだと decltype(c[i]) 型にならない

autoとdecltype(auto)

• autoの部分の型を決定するときに参照情報は無視される

6

//C++14

template <typename Container, typename Index>

auto authAndAccess(Container& c, Index i) {

return c[i];

}

std::deque<int> d;

authAndAccess(d, 5) = 10;

// compile error

// decltype(authAndAccess(d, 5)) is int.

autoとdecltype(auto) –cont.

• decltype(auto)を使えば参照情報は無視されない

7

//C++14

template <typename Container, typename Index>

decltype(auto) authAndAccess(Container& c, Index i) {

return c[i];

}

std::deque<int> d;

authAndAccess(d, 5) = 10;

// decltype(authAndAccess(d, 5)) is int&.

変数宣言でのdecltype(auto)

• autoで無視される参照情報やconst/volatileがdecltype(auto)では無視されない

8

Widget w;

const Widget& cw = w;

auto myWidget1 = cw; // Widget.

decltype(auto) myWidget2 = cw; // const Widget&.

rvalueを渡せない

• constでないlvalue referenceで受ける引数にrvalueは渡せない

9

template <typename Container, typename Index>

decltype(auto) authAndAccess(Container& c, Index i);

std::deque<std::string> makeStringDeque();

auto s = authAndAccess(makeStringDeque(), 5);

// compile error

Universal referenceを使う

• Perfect forwarding

10

//C++14

template <typename Container, typename Index>

decltype(auto) authAndAccess(Container&& c, Index i) {

return std::forward<Container>(c)[i];

}

//C++11

template <typename Container, typename Index>

auto authAndAccess(Container&& c, Index i) ->

decltype(std::forward<Container>c[i]);

std::deque<std::string> makeStringDeque();

auto s = authAndAccess(makeStringDequeu(), 5);

decltypeの特殊ルール

• decltype(lvalue expression)は必ずlvalue referenceになる

11

int x = 0;

decltype(x) y1;

// x is name, so y1’s type is int.

decltype((x)) y2;

// (x) is lvalue expression, so y2’s type is int&.

decltypeの特殊ルール –cont.

•関数の返り値型の推論も同様

12

decltype(auto) f1() {

int x = 0;

return x; // int

}

decltype(auto) f2() {

int x = 0;

return (x); // int&

} ローカル変数の参照を返してしまっている

Item 3 Things to Remember

• decltypeは大体は変数や式の型になる

•型Tの名前以外のlvalue expressionについてのdecltypeは型T&になる.

• C++14はdecltype(auto)をサポートし、auto同様に初期化子から推論するが、decltypeのルールに従う

13

Item 4Know how to view deduced types.

14

推論された型を知る3つの方法

• IDEを使う

•コンパイラを使う

•型を表示するコードを書く• typeid

• Boost TypeIndex

15

IDEを使う

•変数にマウスカーソルを合わせれば型が分かる

16

const int x;

auto y = x; // int y

auto z = &x; // const int *z

IDEを使う –cont.

•複雑な型だと分かりづらい

17

template <typename T>

void f(const T& param) {}

struct Widget {};

std::vector<Widget> createVec() { return {{}}; }

int main(){

const auto v = createVec();

f(&v[0]);

// void f<const std::_Simple_types<std::_Wrap_alloc<

// std::_Vec_base_types<Widget, std::allocator<Widget> >

// ::_Alloc>::value_type>::value_type *>(

// const std::_Simple_types<...>::value_type

// *const &param)

} vc2013だとこう表示される

コンパイラを使う

18

template <typename T>

class TD; // TD is Type Displayer.

const int x = 0;

auto y = x;

auto z = &x;

TD<decltype(y)> yType;

TD<decltype(z)> zType;

> clang++ -std=c++1y t.cpp

t.cpp:11:21: error: implicit instantiation of undefined

template 'TD<int>‘

...

t.cpp:12:21: error: implicit instantiation of undefined

template 'TD<const int *>‘

...

コンパイラを使う –cont.

19

std::map<std::string, std::vector<int>> m;

const auto v = m;

TD<decltype(m)> mType;

> clang++ -std=c++1y t.cpp

...

t.cpp:16:21: error: implicit instantiation of undefined

template

'TD<std::map<std::basic_string<char>, std::vector<int,

std::allocator<int> >,

std::less<std::basic_string<char> >,

std::allocator<std::pair<const std::basic_string<char>,

std::vector<int, std::allocator<int> > > > > >'

TD<decltype(m)> mType;

...

typeidを使う

• i: int

• P: pointer

• K: const

20

const int x = 0;

auto y = x;

auto z = &x;

std::cout << typeid(y).name() << std::endl;

std::cout << typeid(z).name() << std::endl;

> clang++ -sd=c++1y t.cpp && ./a.out

i

PKi

typeidを使う –cont.

21

struct Widget {};

std::vector<Widget> createVec() { return {{}}; }

template <typename T>

void f(const T& param){

std::cout << typeid(T).name() << std::endl;

std::cout << typeid(param).name() << std::endl;

}

const auto v = createVec();

f(&v[0]);

> clang++ -sd=c++1y t.cpp && ./a.out

PK6Widget // 正しいPK6Widget // 誤 const Widget *

// 正 const Widget * const &

Boost TypeIndexを使う

22

#include <iostream>

#include <vector>

#include <boost/type_index.hpp>

template <typename T>

void f(const T& param) {

using boost::typeindex::type_id_with_cvr;

std::cout

<< type_id_with_cvr<T>().pretty_name() << std::endl

<< type_id_with_cvr<decltype(param)>().pretty_name()

<< std::endl;

}

struct Widget {};

std::vector<Widget> createVec() { return {{}}; }

int main() {

const auto v = createVec();

f(&v[0]);

}

Boost TypeIndexを使う –cont.

• TypeIndexはBoost 1.56から使える

23

> clang++ -std=c++1y t.cpp && ./a.out

Widget const*

Widget const* const&

Item 4 Things to Remember

•推論された型はIDEやコンパイラのエラーメッセージ、Boost TypeIndexライブラリにより確認することが出来る

•それらの一部は分かりづらく正確でもないことがあるため、C++の型推論ルールを知っておくことはやはり重要である

24