10

名前のあるタイプがたくさんあります。(これらにはより多くの機能がありますが、この説明のために名前のみが関連しています。) これらの型とその名前は、マクロを使用してコンパイル時に設定されます。

#define DEFINE_FOO(Foo_)                        \
    struct Foo_ : public foo_base<Foo_> {       \
      static char const* name() {return #Foo_;} \
    }

次に、型はコンパイル時のリスト (古典的な単純な再帰的なコンパイル時のリスト) に結合されます。このリストから、オブジェクトの名前を連結してリストの名前を作成する必要があります。

template<class Foo, class Tail = nil>
struct foo_list {
  static std::string name_list() {return Foo::name() + "-" + Tail::name();}
};
template<class Foo>
struct foo_list<Foo,nil> {
  static std::string name_list() {return Foo::name();}
};

コードはここでエラーが含まれる可能性があるところまで煮詰められていますが、実際にはこれはかなりうまく機能します。

コンパイル時に実際によく知られている型を表すかなり長い文字列を実行時に作成してコピーすることを除いて。これは、組み込みデバイスで実行されるかなりパフォーマンスに敏感なコード部分であるため、これを次のように変更したいと思います。

  1. リストの文字列は、理想的にはコンパイル時に作成されるか、それができない場合は実行時に作成されます。
  2. #1 によると、文字列はメモリに固定されているため、C 文字列へのポインターをコピーするだけで済みます。
  3. これは、私たちが今行き詰まっている C++03 でコンパイルされます。

これどうやってするの?

(これにより、これに使用できる汚いトリックの武器が拡大する場合:fooオブジェクトの名前はコードによってのみ作成および読み取られ、foo_list名前文字列のみが人間が判読できると予想されます。)

4

5 に答える 5

4

おそらくブーストのmpl::string. 私のコーヒーが始まったら従うべき例...

編集:だからコーヒーが入った... :)

#include <iostream>

#include <boost/mpl/bool.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/string.hpp>
#include <boost/mpl/vector.hpp>

namespace mpl = boost::mpl;

struct foo
{
  typedef mpl::string<'foo'> name;
};

struct bar
{
  typedef mpl::string<'bar'> name;
};

struct gah
{
  typedef mpl::string<'gah'> name;
};

namespace aux
{

template <typename string_type, typename It, typename End>
struct name_concat
{
  typedef typename mpl::insert_range<string_type, typename mpl::end<string_type>::type, typename mpl::deref<It>::type::name>::type base;
  typedef typename aux::name_concat<base, typename mpl::next<It>::type, End>::name name;
};

template <typename string_type, typename End>
struct name_concat<string_type, End, End>
{
  typedef string_type name;
};

}

template <typename ...Types>
struct type_list
{
  typedef mpl::string<> base;
  typedef mpl::vector<Types...> type_seq;
  typedef typename aux::name_concat<base, typename mpl::begin<type_seq>::type, typename mpl::end<type_seq>::type>::name name;
};

int main(void)
{
  typedef typename type_list<foo, bar, gah>::name tlist_name;
  std::cout << mpl::c_str<tlist_name>::value << std::endl;
}

あなたの状況に合わせて上記を微調整するのに十分な能力があると確信しています。注: 複数文字定数の警告は無視する必要があります...

さらにいくつかの注意事項: に渡される複数文字の定数mpl::stringは 4 文字を超えることはできません。そのため、いくつかの方法でチャンク化 (または個々の文字で構成) する必要があるため、長い文字列になる可能性があります。mpl::string<'this', ' is ', 'a lo', 'ng s', 'trin', 'g'>これができない場合は、その後、上記は機能しません.. :/

于 2013-10-23T07:26:32.550 に答える
3
  1. 文字列を作成することができ、文字列 staticを作成する必要があるのは実行時に 1 回だけで、必要な場合に限られます。
  2. 次に、不必要なコピーがないように、それらの const 参照を返します。

例:

template<class Foo, class Tail = nil>
struct foo_list {
  static const std::string& name_list() {
     static std::string names = Foo::name() + std::string("-") + Tail::name();
     return names;
  }
};

template<class Foo>
struct foo_list<Foo,nil> {
  static const std::string& name_list() {
     static std::string names = Foo::name();
     return names;
  }
};

あなたが書く正確なコードではないかもしれませんが、それはあなたに要点を与えると思います. const char*また、 を実行してa を返すこともできますnames.c_str()

于 2013-10-23T07:34:19.150 に答える
2

言語内ソリューションではなく、外部ビルド ステップの使用を検討できます。たとえば、Clang ベースのツールを作成して関連ファイルを解析しT::name、別の TU で自動的に実装を作成できます。次に、それをビルド スクリプトに統合します。

于 2013-10-30T22:49:49.600 に答える