なんだか雲行きの怪しい雑記帖

ぐだぐだ日記とメモと,あと不定期更新

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

色んなhas_xxx


has_xxxは古い古いと言いつつ,なんだかんだで色々使ってしまうので亜種とかに遭遇しつつ
正直この機能はめちゃくちゃ汎用性が高い(というよりむしろ無駄に汎用性を上げすぎている)ライブラリとか作ってるときにしか使わないんじゃないかなと思いつつ


色んなhas_xxxとそれの実装例というか,まともじゃないC++というか,まあそういうのです

概要

has_xxxと言っても実は色々あります
  • 「型名T::xxx(依存名)があるかどうかを調べる」has_xxx

  • 「テンプレートT::xxxがあるかどうかを調べる」has_xxx

  • 「メンバ変数T::xxxがあるかどうかを調べる」has_xxx

  • 「メンバ関数T::xxxがあるかどうかを調べる」has_xxx




ということで,こういう実装だとこういうクラスが受かる(valueが1となる)についてまとめようと思いました
それとevilなC++コード

テストパターン一覧は次(対象とする依存名はxxxで固定です)
struct nothing{
};

struct type_int_xxx{
typedef int xxx;
};

struct struct_xxx{
struct xxx{};
};

struct template_xxx{
template< typename T > struct xxx{};
};

struct field_int_xxx{
int xxx;
};

struct member_func_xxx{
void xxx();
};

struct static_member_func_xxx{
static void xxx();
};

struct overloaded_member_func_xxx{
void xxx();
void xxx( int );
};

struct template_member_func_xxx{
template< typename T > void xxx();
};

追記:あとから気付いたんですが,C++だとフィールド(field)ではなくメンバ変数(member variable)という方が正しいですね,失敗.メンバ関数(member function)の方はあってるっぽいが…

一応,テスト用の実行コードは次
    // ~~~
// has_xxxはこの辺で定義される
// ~~~

#include <iostream>
int main()
{
using namespace std;

#define TEST( classname ) \
{ cout << #classname << " : " << has_xxx<classname>::value << endl; }

TEST(nothing);
TEST(type_int_xxx);
TEST(struct_xxx);
TEST(template_xxx);
TEST(field_int_xxx);
TEST(member_func_xxx);
TEST(static_member_func_xxx);
TEST(overloaded_member_func_xxx);
TEST(template_member_func_xxx);

return 0;
}


どのhas_xxxの実装でも必要になってくる共通の定義は次
typedef struct{ char c; } true_t;
typedef struct{ char c[2]; } false_t;


has_trait_xxx

has_xxxと言ったら普通はこれだと思う
template< typename T >
struct has_trait_xxx{
template< typename U > static true_t check( U*, typename U::xxx* =0 );
static false_t check( ... );
enum{ value = ( sizeof(check((T*)0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_trait_xxx<T>;

「型名T::xxx(依存名)があるかどうかを調べる」has_xxxです

上と次のは同じ内容で同じ結果,好みで
template< typename T >
struct has_trait_xxx_b{
template< typename U > static true_t check( typename U::xxx* );
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_trait_xxx_b<T>;


ところが上記2つはMSVCとGCCとで動作が違う(GCCとClangは一緒)









テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx111
struct_xxx111
template_xxx100
field_int_xxx000
member_func_xxx000
static_member_func_xxx000
overloaded_member_func_xxx000
template_member_func_xxx000


どこをどうすると「template_xxx」にヒットするのかは分からないが(というかどの型でマッチしてるのか分からないんだが),MSVCだと通る


これを避けるためにBoostではMSVCの時にだけ次のようなテンプレートで分岐をかけるようなコードを使う
template< typename T >
struct has_trait_xxx_sfinae{
template< typename U > struct sfinae_helper{ typedef void type; };
template< typename U, typename V =void > struct check{ enum{ value =false }; };
template< typename U > struct check< U, typename sfinae_helper<typename U::xxx>::type >{ enum{ value =true }; };
enum{ value = ( check<T>::value ) };
};

template< typename T >
using has_xxx = has_trait_xxx_sfinae<T>;


こうすると見事,結果が一致する,MSVC不思議










テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx111
struct_xxx111
template_xxx000
field_int_xxx000
member_func_xxx000
static_member_func_xxx000
overloaded_member_func_xxx000
template_member_func_xxx000


最初の2つが「オーバーロードによる解決」で,最後のが「テンプレートとSFINAEによる解決」らしく,上記例のように微妙に結果が異なったりする時があるようです
次から説明していくやつとかは基本的に「オーバーロードによる解決」の方を使っていきます,書くの楽だし

has_template_xxx

依存名「T::xxx」がtemplateの場合にマッチするようなhas_xxxです
template< typename T >
struct has_template_xxx{
template< template< typename ...Args > class U > struct substitute_any{};
template< typename U > static true_t check( substitute_any<U::template xxx>* );
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_template_xxx<T>;


カッチョいいのでVariadicTemplatesを使いました
 (書いてませんでしたがTemplateAliasesも使っているので,g++は4.7以降じゃないとコンパイル通らんすよね)

依存名がtemplateの場合に必要になる「template」キーワードの位置が初見だと気持ち悪いですよね,「U::template xxx」ですから









テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx000
struct_xxx000
template_xxx111
field_int_xxx000
member_func_xxx000
static_member_func_xxx000
overloaded_member_func_xxx000
template_member_func_xxx000


ちなみにBoostさんの「BOOST_MPL_HAS_XXX_TEMPLATE_DEF」と「BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF」は,VariadicTemplatesを使わない環境でも動くように書いていて,どう対処しているのかというと
template< typename T >
struct has_template_xxx_no_variadic{
template< template< typename A0 > class U > struct substitute1{};
template< template< typename A0, typename A1 > class U > struct substitute2{};
template< template< typename A0, typename A1, typename A2 > class U > struct substitute3{};
// ~~以下もっと続く~~
template< typename U > static true_t check( substitute1<U::template xxx>* );
template< typename U > static true_t check( substitute2<U::template xxx>* );
template< typename U > static true_t check( substitute3<U::template xxx>* );
// ~~以下もっと続く~~
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_template_xxx_no_variadic<T>;

のような感じです
なので,めちゃくちゃテンプレート引数が多いのにはマッチしないので,例えば
struct template4_xxx{
template< typename T0, typename T1, typename T2, typename T3 > struct xxx{};
};
struct template10_xxx{
template<
typename T0, typename T1, typename T2,
typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9
>
struct xxx{};
};

#include <boost/version.hpp>
#include <boost/mpl/has_xxx.hpp>
BOOST_MPL_HAS_XXX_TEMPLATE_NAMED_DEF( has_template_xxx_boost, xxx, false );

#include <iostream>
int main()
{
using namespace std;
cout << "boost_version : " << BOOST_LIB_VERSION << endl;
cout << "template4_xxx : " << has_template_xxx_boost<template4_xxx>::value << endl;
cout << "template10_xxx : " << has_template_xxx_boost<template10_xxx>::value << endl;
return 0;
}

とすると,「template4_xxx」の方はマッチするけど「template10_xxx」だとマッチしないなんていうことがある
 (ちなみに,検証に使用したBoostのバージョンは「1_46_1」と「1_55:revision86344」です)

has_member_xxx

メンバ変数とメンバ関数いずれかにマッチするようなhas_xxx
ちなみにこれが今回試した各コンパイラで一番結果がバラバラになりやすいです
template< typename T >
struct has_member_xxx{
template< typename U > static true_t check( decltype( &U::xxx )* );
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_member_xxx<T>;

のーまるに書けばおそらくこれが順当だと思うんですが,メンバ関数までとれるのはちょっと意外ですね
それはさておき,実はこれMSVC2013及びMSVC2012ではコンパイル時にコンパイラが落ちるっていう挙動されてチェックができないです;;










テストケースMSVC2013g++-4.8.1clang++-3.3
nothing-00
type_int_xxx-00
struct_xxx-00
template_xxx-00
field_int_xxx-11
member_func_xxx-11
static_member_func_xxx-11
overloaded_member_func_xxx-00
template_member_func_xxx-00

いやぁVC駄目ですね,MSVCが落ちなければこれあってると思うんですけどね

ちなみにSFINAEによる解決方法をとってもMSVCはやらかしてくれます
template< typename T >
struct has_member_xxx_sfinae{
template< typename U > struct sfinae_helper{ typedef void type; };
template< typename U, typename V =void > struct check{ enum{ value =false }; };
template< typename U > struct check< U, typename sfinae_helper<decltype(&U::xxx)>::type >{ enum{ value =true }; };
enum{ value = ( check<T>::value ) };
};

template< typename T >
using has_xxx = has_member_xxx_sfinae<T>;

コンパイルは通ります,ただ全部falseになります










テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx000
struct_xxx000
template_xxx000
field_int_xxx011
member_func_xxx011
static_member_func_xxx011
overloaded_member_func_xxx000
template_member_func_xxx000

いやぁVC駄目ですね(再度

MSVCは依存名「T::xxx」を直接記述するとどうやら落ちるっぽいのでこういう風に書きなおしたりしてみます
template< typename T >
struct has_member_xxx_b{
template< typename U > static U&& declval();
template< typename U > static true_t check( decltype( declval<U>().xxx )* );
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_member_xxx_b<T>;

ちなみにこれ試したコンパイラ全てで結果が違うパターンです










テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx000
struct_xxx000
template_xxx000
field_int_xxx111
member_func_xxx100
static_member_func_xxx110
overloaded_member_func_xxx000
template_member_func_xxx000

わあびみょう
しかしg++とclang++が違うのはなかなかないケースだと思うんですがね

ここで,なぜかこう書くとうまくいったりするんですね
template< typename T >
struct has_member_xxx_c{
template< typename U > static U&& declval();
template< typename U > static true_t check( decltype( declval<U>().xxx() )* );
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_member_xxx_c<T>;











テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx000
struct_xxx000
template_xxx000
field_int_xxx000
member_func_xxx111
static_member_func_xxx111
overloaded_member_func_xxx111
template_member_func_xxx000

僕らが見たかったのはこの表だ…!!!!

喜ぶのも束の間,実はこれもちょっとトリックがありまして,よく見てください
全てのコンパイラの結果は一致していますが,メンバ変数は「false」です,代わりにオーバーロードしているメンバ関数が「true」です

これは要するに「declval<T>.xxx()」が評価可能な式であるかどうかを見ているだけなので,メンバ変数はそこで落ちますし,全てのメンバ関数を網羅しているわけではないんですよね
事実,一引数以上をとるような関数(引数省略がないと仮定して)の場合はマッチしません
/*
has_member_xxx_cの定義とかは省略
*/

struct member_func_xxx{
void xxx();
};

struct member_func_p1_xxx{
void xxx( int );
};

struct static_member_func_xxx{
static void xxx();
};

struct static_member_func_p1_xxx{
static void xxx( int );
};

#include <iostream>
int main()
{
using namespace std;
cout << "member_func_xxx : " << has_member_xxx_c<member_func_xxx>::value << endl;
cout << "member_func_p1_xxx : " << has_member_xxx_c<member_func_p1_xxx>::value << endl;
cout << "static_member_func_xxx : " << has_member_xxx_c<static_member_func_xxx>::value << endl;
cout << "static_member_func_p1_xxx : " << has_member_xxx_c<static_member_func_p1_xxx>::value << endl;
/*
結果:
member_func_xxx : 1
member_func_p1_xxx : 0
static_member_func_xxx : 1
static_member_func_p1_xxx : 0
*/
return 0;
}

とても惜しい線をいってる気がする…

ところで,依存名の型「T::xxx」がマッチしない理由は,「typename」がついてないからだったりします
C++よくできてるな


なお,TrailingReturnTypeを使うとちょっと格好良くなります
template< typename T >
struct has_member_xxx_d{
template< typename U > static U&& declval();
template< typename U > static auto check( U v ) -> decltype( v.xxx(), true_t() );
static false_t check( ... );
enum{ value = ( sizeof(check(declval<T>())) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_member_xxx_d<T>;


has_overloaded_member_func_xxx

前節で見た内容ではメンバ関数だけど受かってないケースがあったと思います
そう,オーバーロードされたメンバ関数の場合「overloaded_member_func_xxx」ですね
なぜこれがfalseなのかというと,
”メンバ関数がある…けれど関数シグネチャが分からない→関数の実体が特定できない→戻り値も分からない→\コンパイルエラー/”
って流れになってしまうようです

そこで,「has_xxx時にテンプレートで引数の型を指定すればよいのでは…」という話になるとこうできると思いました
template< typename T, typename ...Args >
struct has_overloaded_member_func_xxx{
template< typename U > static U&& declval();
template< typename U > static true_t check( decltype( declval<U>().xxx( declval<Args>()... ) )* );
template< typename U > static false_t check( ... );
enum{ value = ( sizeof(check<T>(0)) == sizeof(true_t) ) };
};

template< typename T >
using has_xxx = has_overloaded_member_func_xxx<T,int>;

最後のTemplateAliasesで地味にint指定しているのに注意してください
これで,「<any> T::xxx( int )」な関数シグネチャの関数にマッチします










テストケースMSVC2013g++-4.8.1clang++-3.3
nothing000
type_int_xxx000
struct_xxx000
template_xxx000
field_int_xxx000
member_func_xxx000
static_member_func_xxx000
overloaded_member_func_xxx111
template_member_func_xxx000

マッチするようです(確信)
ただ,「declval()」で引数を作っているため,暗黙的変換の影響は受けますので,厳密な関数シグネチャのチェックにはならないですね

おわりに

と,「そんなのBoost.TTIにあるやん!」と言われても何もおかしくないような記事でした
ってかBoost.TTIには
  • メンバ関数があるかどうかのチェック

  • メンバ変数があるかどうかのチェック

  • 指定した型を持つメンバ変数があるかどうかのチェック

とかあるし,明らかに高性能なのは調べたら分かったんですが,何分なぜかMSVCだとコンパイル通らなくて追うのは色々断念しました,ふみゅう
全ては「&U:xxx」が通らないせいだと思うんですが,まじでこれはどうすればいいんですかね…

一応今回あげたのを組み合わせていけばある程度「メンバ変数はあるか」とかまで限定できるように思えるんですが,直接それを推定する記述の仕方がないので書いてないです
悔しい…

…それはそうと…比較内容多くて,地味に疲れたにゃす
それではまた…
スポンサーサイト

has_xxxした後型「T::xxx」が欲しい時の話

こうして少しずつ変態C++力を上げていこうとする試み

友人曰く「でもhas_xxxってもう別に新しい感じは全くしないし,今更すぎて反応に困る」

…せやな…現代C++erの黒魔術力の足しにもなりませんよね…ウン…
続きを読む

InitializerListとUniformInitialization(とMSVCと)

某勉強会の生放送を見てて,UniformInitializationの書き方とInitializarListの書き方がかぶってなんだか面倒くさいなぁと思っていたのですが,気になったこともあったので色々と試していました



UniformInitialization

C++から導入されたクラスですが,ローカルでインスタンスを初期化する際は「()」によりコンストラクタに引数を渡します.


#include <iostream>
using namespace std;

class foo
{
public :
foo(){ cout << "foo()" << endl; }
foo( int ){ cout << "foo(int)" << endl; }
};

int main()
{
// ローカル変数を初期化する際にコンストラクタに引数渡す
foo a( 0 );

return 0;
}

foo(int)


「using namespace std;」すんなよとか細かいところは今は目を瞑って下さい,本筋ではありません
さて,コンストラクタに引数を渡す場合は何も問題ありません.
ただ,引数を渡さない場合同じ書き方ができません.


// ~略~
int main()
{
// ローカル変数を初期化する際にコンストラクタに引数渡す
foo a( 0 );

// コンストラクタに引数を渡さない場合
foo b();// 正しくない(意図した通りではない),これはfoo型を返す引数なし関数bのプロトタイプ宣言と解釈される
foo c;// OK

return 0;
}

foo(int)
foo()


「b」も「c」も同じことをしたいのに,コンストラクタに引数を渡す渡さないで書き方が変わるのなんか嫌ですよね.
ただ,この「foo b();」はCとの互換のために変更することはできないので,思い切って「{}」を使ってコンストラクタ呼ぼうぜっていうのがUniformInitializationです.


// ~略~
int main()
{
// ローカル変数を初期化する際にコンストラクタに引数渡す
foo a{ 0 };

// コンストラクタに引数を渡さない場合
foo b{};// OK
foo c;// OK

return 0;
}

foo(int)
foo()
foo()




InitializerList

やりたい事的にはUniformInitializationとInitializerListにつながりはないです,とりあえず言っとくと.

C及びC++ではプリミティブの配列型では「= { ... }」と書くことで各要素を初期化できてました.

#include <iostream>
using namespace std;

int main()
{
int a[] ={ 0, 1, 2, 3, 4 };
for( const auto it : a )
{
cout << it << ",";
}

return 0;
}

0,1,2,3,4,


これをユーザ定義型とか他の型でも使えるようにしちゃおうってのがInitializerListです


#include <iostream>
#include <initializer_list>
using namespace std;

class foo
{
public :
foo( initializer_list<int> il )
{
cout << "foo(initializer_list):size=" << il.size() << endl;
for( const auto it : il ) cout << it << ",";
cout << endl;
}
};

int main()
{
foo a ={ 0, 1, 2, 3, 4 };

return 0;
}

foo(initializer_list):size=5
0,1,2,3,4,


MSVC2013Previewでは既にstd::vector等でこれらが実装されていますね.

これとStructのAggregateInitializationにより非常に強力な書き方が出来るんですが,今回はお題と外れるのでそれについては言及しません.
興味のある型はaggregate_initializationとか見ればいいんじゃないかな.

ちなみにこのInitializerList,実は「{...}」の項がinitializer_list型と解釈されるってのも覚えておくと色々便利.

#include <iostream>
#include <initializer_list>
using namespace std;

int main()
{
initializer_list<int> a = { 2, 3, 5, 7, 11 };
for( const auto it : a )
{
cout << it << ",";
}

return 0;
}

2,3,5,7,11,


若干余談になりますが,initializer_listはcbegin/cendではなくbegin/endを持つそうです.
initializer_listは変更不能なインスタンスしかないのでcbegin/cendを持つのが正しいように思えますが,これはrange-based forがbegin/endを持つコンテナを対象にする事との関係だとか.
実際,initializer_listのbegin/endはconst_iteratorと同じ型を返すので内部弄れない.



本題:UniformInitializationとInitializerList


さて,「{...}」はinitializer_list型として解釈されることは書きました.
なので,次の二つのローカル変数aとbの初期化は実質等しい動作をします.

#include <iostream>
#include <initializer_list>
using namespace std;

class foo
{
public :
foo( initializer_list<int> il )
{
cout << "foo(initializer_list):size=" << il.size() << endl;
for( const auto it : il ) cout << it << ",";
cout << endl;
}
};

int main()
{
foo a ={ 0, 1, 2, 3, 4 };
foo b( { 5, 6, 7, 8, 9 } );

return 0;
}

foo(initializer_list):size=5
0,1,2,3,4,
foo(initializer_list):size=5
5,6,7,8,9,


注意(NOTICE)!
ところでこのコード,MSVC12(MSVS2013Preview)だとコンパイル通らないコードなんですが,実は今回の記事はこういうMSVCの微妙なコンパイルエラーが起きるコードと起きないコードについて実験を行っています.
上記コードはg++とclang++では通るので,仕様的にはOKだと思います.

ここにUniformInitializationが入ってくると,bの書き方がこうなります

#include <iostream>
#include <initializer_list>
using namespace std;

class foo
{
public :
foo( initializer_list<int> il )
{
cout << "foo(initializer_list):size=" << il.size() << endl;
for( const auto it : il ) cout << it << ",";
cout << endl;
}
};

int main()
{
// 旧式? の書き方
foo b( { 5, 6, 7, 8, 9 } );

// uniform initialization+initializer_list的な書き方
foo c{ { 5, 6, 7, 8, 9 } };

return 0;
}

foo(initializer_list):size=5
5,6,7,8,9,
foo(initializer_list):size=5
5,6,7,8,9,


なんか気持ち悪くなってきましたね….
ところで,UniformInitializationとInitializerListの二つの規格が入ったのがほぼ同時期なためなのかは全くわかりませんが,cの書き方に関しては外側の「{}」は省略できちゃいます.
(と言うと語弊があるので補足すると,UniformInitializationの場合は引数はinitializer_listに変換され得るし,更にinitializer_listを食うコンストラクタがあった場合はそれを優先するという動作になるようで)


#include <iostream>
#include <initializer_list>
using namespace std;

class foo
{
public :
foo( int, int, int, int, int ){ cout << "foo(int,int,int,int,int)" << endl; }
foo( initializer_list<int> il )
{
cout << "foo(initializer_list):size=" << il.size() << endl;
for( const auto it : il ) cout << it << ",";
cout << endl;
}
};

int main()
{
// 旧式? の書き方
foo b( { 5, 6, 7, 8, 9 } );

// uniform initialization+initializer_list的な書き方
foo c{ { 5, 6, 7, 8, 9 } };

// uniform initializatiomただしinitializer_listが優先される
foo d{ 5, 6, 7, 8, 9 };

return 0;
}

foo(initializer_list):size=5
5,6,7,8,9,
foo(initializer_list):size=5
5,6,7,8,9,
foo(initializer_list):size=5
5,6,7,8,9,


はい,dの場合でもInitializerListの方が優先されてますね.
それにしてもうーん,今更だがこの言語むずいな….



実験:


MSVC2013PreviewになってUniformInitializationとかInitializerListとか対応したらしいので,早速試してみようということで実験しました.
一応g++やclang++など他のコンパイラだとコンパイル出来る出来ないの比較もちょっと.

ちょっと長いけどテストコードは以下.
MSVCだけ通るきもいのがありますが,まぁ置いとけ.

#include <iostream>
#include <initializer_list>
using namespace std;

class foo
{
public :
foo( initializer_list<int> il ) { }
};

int main()
{
// initializer_list
foo a ={ 0, 1, 2, 3, 4, 5 };

// initializer_listのリテラルを渡す場合
foo b( { 0, 1, 2, 3, 4, 5 } );

// 一旦ローカル変数に落としてから渡す場合
initializer_list<int> il ={ 0, 1, 2, 3, 4, 5 };
foo c( il );

// uniform initialization+initializer_list的な書き方
foo d{ { 0, 1, 2, 3, 4, 5 } };

// uniform initializatiom
foo e{ 0, 1, 2, 3, 4, 5 };

// 何やってるか意味不明だと思いますが,っていうか意味不明ですが,
// 通るコンパイラがあるんですよ
foo f{ { { { 0, 1, 2, 3, 4, 5 } } } };

// 一時変数的な扱いをした場合
auto g = foo( { 0, 1, 2, 3, 4, 5 } );
auto h = foo( il );
auto i = foo{ { 0, 1, 2, 3, 4, 5 } };
auto j = foo{ 0, 1, 2, 3, 4, 5 };
auto k = foo{ { { { 0, 1, 2, 3, 4, 5 } } } };

return 0;
}


比較コンパイラ(関係ないと思うけどOSも書いとく系)

  • MSVS Express 2013 Preview(Win8x86)

  • g++-4.7.2(Ubuntu12.04x86Desktop on VMPlayer)

  • clang++3.4-1 exp1(Ubuntu12.04x86Desktop on VMPlayer)



g++は4.7なのにclangは3.4かよとかいうツッコミに関しては,Clangはバージョンが古いとオレオレライブラリを食わせる時セグフォるので最新版入れてるだけだったりする.
他に使うメジャーなコンパイラはないと思うので,この3つで.

試した結果,MSVS2013Previewに関しては微妙な結果というかバグみたいなのがでて残念な感じになりました.











コンパイラMSVC12Previewg++-4.7.2clang++3.4-1 exp1
case : aOKOKOK
case : bCompilationErrorOKOK
case : cOKOKOK
case : dOKOKOK
case : eOKOKOK
case : fOKCompilationErrorCompilationError
case : gOKOKOK
case : hOKOKOK
case : iOKOKOK
case : jOKOKOK
case : kOKCompilationErrorCompilationError

一時変数にしたら通るあたりbは完全にMSVCのバグですねこれ…まあPreviewだししょうがない

それはそれといつconstexpr実装されるんですかね(ゲス顔

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。