忍者ブログ

どっかのゆとりのチラシの裏

plasma_effectのメモ帳的ブログのようなsomething

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

VC++ in VS2015の機能 part02 ユーザー定義リテラル

「VS2015の記事を見てたはずだがいつの間にかconstexprの記事になっていた」という意見が出た。VC++固有の機能の記事なんて俺が書けるわけ無いだろ!!!!

2015年7月20日にVisual Studio 2015がリリースされた。当然VC++も新しくなったわけだがそのうち新しく追加された機能を出来る限り毎日記事にしようと思う。
本日はそのpart02、ユーザー定義リテラルだ。

ある型の一時変数を作るのにわざわざ関数を使いたくはないという時があったりなかったりする。例えば複素数値型など。

struct complex{
int re_,im_;
constexpr complex(int re=0, int im=0):re_(re),im_(im){}
complex(complex const&)=default;
complex(complex&&)=default;
~complex()=default;
};

int main(){
complex v = complex(0,2);//2iって書きたい
}



100uでunsigned int型の100を表すようにユーザー定義のリテラルを使いたい。
operator""でそのようなユーザー定義のリテラルを作ることができる。

struct complex{
int re_,im_;
constexpr complex(int re=0, int im=0):re_(re),im_(im){}
complex(complex const&)=default;
complex(complex&&)=default;
~complex()=default;
};

complex operator"" _i(unsigned long long int v){
return complex(0, v);
}

int main(){
complex v = 2_i;//complex(0, 2);
}



ユーザー定義リテラルにはいくつか成約がある。まず引数の型にはunsigned long long intやlong doubleといった一部の型しか使えない。

int operator"" _hoge(unsigned long long int v){//OK
return static_cast<int>(v);
}
int operator"" _piyo(int v){
return static_cast<int>(v);
}

int main(){}



また_(アンダーバー)から始まらないリテラルは予約されてるので使うと色んな人に怒られる。コンパイラにも怒られる。

int operator"" hoge(unsigned long long int v){
return static_cast<int>(v);
}//コンパイルは通るが警告が出る

int main(){}



あと規格的には""と_の間に空白文字(スペースなど)が必要…らしい。別にMSVCでもgccでもclangでもスペース入れなくても通るんだから気にする必要とかないんじゃないのかこれ

unsigned long long intの他に使える型を紹介する。まずはlong double

int operator"" _to_int(long double d){
return static_cast<int>(d);
}

int main(){
int v = 2.0_to_int;
}



char const*

#include<utility>
int operator"" _hoge(char const*, std::size_t s){
return s;
}

int main(){
int v = "test"_hoge;
}



あとはwchar_tとかそこら辺である。

ユーザー定義リテラルでは基本的にtemplateが使えない。ただしvariadic templateを使用できる唯一の例が存在する。

template<char... Cs>struct string_t{};
template<char... Cs>string_t<Cs...> operator"" _hage(){
return string_t<Cs...>{};
}

int main(){
auto x = 12345_hage;//string_t<'1', '2', '3', '4', '5'>
}




この場合引数は付けない。unsigned long long intのみに対応する。

参考
本の虫 ユーザー定義リテラルのすべて:http://cpplover.blogspot.jp/2012/02/blog-post_16.html
C++11の文法と機能(C++11: Syntax and Feature):http://ezoeryou.github.io/cpp-book/C++11-Syntax-and-Feature.xhtml#over.literal

余談
記事書いてて公開するボタン押したら勝手にレイアウト変えられててマジギレだしブログ変えたい
PR

VC++ in VS2015の機能 part01 constexpr

久しぶりにブログ開いたら広告出てて泣いた。というわけで記事を書くことにする。

2015年7月20日にVisual Studio 2015がリリースされた。当然VC++も新しくなったわけだがそのうち新しく追加された機能を出来る限り毎日記事にしようと思う。
本日はそのpart01、constexprだ。

constexprはC++11で追加された機能で、現在のC++14では更にパワーアップしているのだが、Microsoftの脳みそが2011年から進んでないのでC++11版のconstexprを紹介する。

コンパイル時において定数式はその場で計算される。定数式とは例えば以下の様なもの。

int main(){
const int v = 1 + 2;//明らかに3
const int u = 3 * 5;//明らかに15
}

一方でコンパイル時に使える定数(以下コンパイル時定数)が存在する。定数式で初期化されているconst定数がそれ。上の例で言えばvもuもコンパイル時定数である。コンパイル時に使えるとは例えばtemplate引数に渡せる。


template<int N>struct test{
static int get(){
return N;
}
};

int main(){
const int v = 1 + 2;
const int u = test<v>::get();
}

この例ではvはコンパイル時定数なのでtemplateクラスtestの引数に渡せる。一方でstaticメンバ関数getは定数式ではないのでuはコンパイル時定数でない定数である。この場合uはtemplate引数に渡せない。

変数に対するconstexprは変数がコンパイル時定数であることを保証する指定子である。型はあくまでconstであり、constexprではない。


int hoge(){return 0;}

int main(){
constexpr int v = 0;//OK
constexpr int u = hoge();//NG
}

一方で関数に対するconstexprはその関数を定数式として扱えるようにする指定子である。constexpr関数の中身は実質的にreturn文一つでなければならない。

constexpr int hoge(){return 0;}
constexpr int fact(int n){return n==0 ? 1 : n*fact(n-1);}

int main(){
constexpr int v = 0;//OK
constexpr int u = hoge();//OK
constexpr int w = fact(5);//OK
}

return文一つといっても条件演算子が使えるので関数型言語に慣れている人なら親しみを持てるのではないだろうか。

定数式とできるのは組み込み型がまず上げられるがユーザー定義でconstexpr定数、またはconstexpr関数に使えるクラスも作ることができる。定数式に使える型をリテラル型と言う。

リテラル型には組み込み型やその配列がまず考えられるが、それらを組み合わせたユーザー定義型でリテラル型となる条件は以下のとおり。
・デストラクタがトリビアル
・次のどちらかを満たす「aggregateである」「コピーでもムーブでもないconstexprコンストラクタ、またはtemplateなコンストラクタを持つ」
・staticでないメンバ変数が全てvolatileでもないリテラル型
例えば以下の様なクラスがリテラル型となる。

struct pair{
int x_,y_;
constexpr pair(int x=0,int y=0):x_(x),y_(y){}
pair(pair const&)=default;
pair(pair&&)=default;
~pair()=default;
};

int main(){
constexpr pair p(0,1);
constexpr int u = p.x_;
constexpr int v = p.y_;
}

そういえば上のコードでわかるようにVS2015ではムーブコンストラクタもdefault宣言できるようになった。むしろ今までできなかったほうがおかしい。

リテラル型やconstexprに関する活用法はここでは書かない。様々な場所で論じられているのでそちらを参考にして欲しい。

参考ページ
中3女子でもわかる constexpr:http://www.slideshare.net/GenyaMurakami/constexpr-10458089
リテラル型クラスの条件、および「中3女子でもわかる constexpr」の訂正:http://boleros.hateblo.jp/entry/20130718/1374155184
C++11の文法と機能(C++11: Syntax and Feature):http://ezoeryou.github.io/cpp-book/C++11-Syntax-and-Feature.xhtml#basic.types

余談
実はVC++のconstexprでバグとかないかのチェックとかまだしてないしもしかしたら規格に反する動作をするかもしれない。

C++2zでは動的関数生成が追加される

C++2zでは文字列から関数オブジェクトを生成されるtemplate関数compilingがfunctionalヘッダに追加される。std名前空間における宣言は以下のとおりだ。
template<class FunT, std::size_t Alignment, class ForwardIterator>function<FunT>compiling(ForwardIterator first, ForwardIterator last);
使い方は以下のとおりだ。

#include<functional>
#include<iostream>
#include<string>

int main()
{
std::string str="int add(int n,int m){return n + m;}";
auto func = std::compiling<int(int, int), 8>(str.begin(), str.end());
std::cout<< func(1, 2) <<std::endl;
}



FunTは返り値のstd::functionの型を指定し、Alignmentはその関数で確保される最大のメモリ容量を指定する。
ここで注意したいのはcompilingでは以下の機能しか使えない。すなわち
・組み込み型の変数定義
・組み込み型の演算子
・if, for, while文
・return文
関数呼び出しやユーザー定義型が使えないことには要注意だ。
また文字列が不合理な場合以下の様な例外が投げられる。複数の例外に当たる場合上のものが優先される。
・文法的に意味を成さない(typedefや関数が使われている場合含む)→std::bad_function_parsing
・返り値がFuncTで指定したものと合わない→std::bad_function_type
・Alignmentで指定した以上のメモリを必要とする→std::memory_over_exception
実行時に文字列を与えてそこから関数を生成することも可能となる。また将来的にはcompilingの文鳥言語版compiling_bunchoも導入される予定だ。

カレンダー

10 2024/11 12
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

フリーエリア

最新CM

[02/12 kariya_mitsuru]
[10/14 どっかの京大生o]
[10/04 どっかのZ会生y]
[07/31 どっかのZ会生y]
[07/31 GNR]

プロフィール

HN:
plasma_effect
性別:
非公開

バーコード

ブログ内検索

最古記事

(06/08)
(06/18)
(06/21)

P R