C ++で条件付きtypedefを作成する方法


89

私はこのようなことをやろうとしています:

#include <iostream>
#include <random>

typedef int Integer;

#if sizeof(Integer) <= 4
    typedef std::mt19937     Engine;
#else
    typedef std::mt19937_64  Engine;
#endif

int main()
{
    std::cout << sizeof(Integer) << std::endl;
    return 0;
}

しかし、私はこのエラーを受け取ります:

error: missing binary operator before token "("

条件付きtypedefを正しく作成するにはどうすればよいですか?


25
プリプロセッサはsizeof、やその他のC ++構造について何も知りません。それは確かにあなたが自分で作成したことについて知らないtypedefこともまだ解析されていないとして、。
オービットのライトネスレース2013年

2
あなたは使うことができenable_ifたりconditional、条件付きのtypedefを定義することができますが、そのためのプリプロセッサを使用することはできません。
Bartek Banachewicz 2013

1
@LightnessRacesinOrbit:前処理とコンパイルはGCCに統合されているため、ソフトウェア処理コードがユーザー作成の型定義を認識していないだけでなく、GCCの場合はfalseであることがわかっています。sizeofプリプロセッサー条件で機能しない理由は、言語がそのように定義されているためであり、実装がどのように機能するかではありません。
Eric Postpischil 2013

1
@LightnessRacesinOrbit:翻訳フェーズでは、処理の順序ではなく、構文とセマンティクスを定義します。C ++ 2011(N3092)2.2 [lex.phases]注11に従い、「実装はこれらの個別のフェーズが発生するかのように動作する必要がありますが、実際には異なるフェーズが一緒にフォールドされる場合があります。」これは実装がどのように機能するかというあなたの主張が間違っていることを示しているので、GCCに関する私のポイントは関連があります。言い換えれば、あなたのコメント、特定の実装方法がこれを防ぐと主張しています。しかし、これを防ぐのは実装ではありません(それが可能です)。言語の定義です。
Eric Postpischil 2013

1
@エリック:実装について何も主張するつもりはなかった。私は確かに特定のものについて言及しなかった。私のコメントは、あなたと同じように、as-ifルールの対象となる動作を述べています。私たちが実際にここで何かに異議を唱えているとは思いません。あなたの言語弁護士も鏡から直接出てきたのかもしれません。:)
2013

回答:


139

std::conditionalC ++ 11 のメタ関数を使用します。

#include <type_traits>  //include this

typedef std::conditional<sizeof(int) <= 4,
                         std::mt19937,
                         std::mt19937_64>::type Engine;

で使用するタイプがsizeofテンプレートパラメータである場合はT、次のように使用する必要がありますtypename

typedef typename std::conditional<sizeof(T) <= 4, // T is template parameter
                                  std::mt19937,
                                  std::mt19937_64>::type Engine;

または次のようにEngine依存しTます:

template<typename T>
using Engine = typename std::conditional<sizeof(T) <= 4, 
                                         std::mt19937,
                                         std::mt19937_64>::type;

これは柔軟です。次のように使用できるからです。

Engine<int>  engine1;
Engine<long> engine2;
Engine<T>    engine3; // where T could be template parameter!

4
+1マイナーヒント:sizeof(int) <= 464ビットのWindowsマシンでは、GCC(MinGW)x64コンパイラがを提供するため、チェックはあまり移植性のない方法sizeof(int) = sizeof(long) = 4です。より良い方法はでしょうsizeof(void*) <= 4
legends2k 2013

@ legends2k:つまりEngine<void*> engine4;?;-)
Nawaz

2
@Nawaz:もちろんそうではありません:)私はstd::conditional<sizeof(void*) <= 4, std::mt19937, std::mt19937_64>最初のコードスニペットで意味しました。
legends2k 2013

1
@ legends2k:私があなたに提供した場合、なぜそれを使うのEngine<void*>ですか?:P
Nawaz 2013

@Nawaz:ハハ...それは本当です。ただし、OPはおそらく、int:) のサイズに基づいてアーキテクチャを検出する際の落とし穴を知っているはずだと思いました
legends2k

35

std::conditionalあなたを使ってそれをそうすることができます:

using Engine = std::conditional<sizeof(int) <= 4, 
                               std::mt19937, 
                               std::mt19937_64
                               >::type;

を実行したい場合は、typedefそれも実行できます。

typedef std::conditional<sizeof(int) <= 4, 
                         std::mt19937, 
                         std::mt19937_64
                         >::type Engine

typenameここに必要はありません
gx_ 2013

@gx_うん、具象型ではなく、テンプレートでの作業をそこに置くことに慣れていました。
Rapptz 2013

1
@LightnessRacesinOrbitさて、少し修正しました。
Rapptz 2013

5

C ++ 11を使用できない場合(使用する予定がある場合は使用std::mt19937できるようですが)、Boost Metaprogramming Library(MPL)を使用して、C ++ 11のサポートなしで同じことを実装できます。以下はコンパイル可能な例です:

#include <boost/mpl/if.hpp>
#include <iostream>
#include <typeinfo>

namespace mpl = boost::mpl;

struct foo { };
struct bar { };

int main()
{
    typedef mpl::if_c<sizeof(int) <= 4, foo, bar>::type Engine;

    Engine a;
    std::cout << typeid(a).name() << std::endl;
}

これは、ここでは4バイトなfooので、私のシステムでのマングルされた名前を出力しintます。


1
if_c代わりに使用しないのはなぜですか?書く(そして理解する)のはもっと簡単でなければなりません:mpl::if_c<sizeof(int)<=4, foo, bar>::type。だよね?
Nawaz 2013

1
@Nawaz:確かに、それはいくつかの点で優れています。忘れちゃったmpl::if_c。代わりにそのアプローチを使用するように例を更新しました。
Jason R
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.