スポンサーリンク

ICUライブラリのicu::UnicodeStringを前方宣言したらC2757が発生

経緯

icuライブラリのラッパーを作成したくなり、hppにicu::UnicodeStringのポインタを持たせ、cpp内でnewする構造にした。この時、前方宣言したらエラーC2757が発生。原因はicuという名前空間が実は存在していないかららしい。

まず、エラーの出るコードは以下。

エラーの出るコード

icuwrap.hpp

#pragma once

// クラスが名前空間に入っている時は前方宣言をこうする
namespace icu{ // C2757
  class UnicodeString;
}

// icu::UnicodeStringのラッパー
struct MyICU {
  icu::UnicodeString* ustr;
};

// ICUライブラリのUnicodeStringのラッパーを作成
MyICU make_my_icu(const char16_t* text);

icuwrap.cpp

#include <unicode/ucnv.h>
#include <unicode/brkiter.h>

#include"icuwrap.h"

// 要リンク
#pragma comment(lib, "icuuc.lib")
#pragma comment(lib, "icudt.lib")


MyICU make_my_icu(const char16_t* text) {
  MyICU tmp;

  tmp.ustr = new icu::UnicodeString(text);

  return tmp;
}

main.cpp

#include "icuwrap.h"

int main()
{
  MyICU micu = make_my_icu(u"hello");

}

すると以下のコンパイルエラーが発生する

error C2757: ‘icu’: この名前のシンボルは既に存在します。この名前を名前空間名として使用することはできません。

原因

構造

icuというリテラルは unicode/uversion.h の中で定義されているのだが、実はこれはU_ICU_NAMESPACEマクロで生成されたもののエイリアスで、さらにこれはU_ICU_ENTRY_POINT_RENAMEマクロで作成されている

unicode/uversion.h    Line 105~

#       define U_ICU_NAMESPACE U_ICU_ENTRY_POINT_RENAME(icu)
        namespace U_ICU_NAMESPACE { }
        namespace icu = U_ICU_NAMESPACE;

ではこの U_ICU_ENTRY_POINT_RENAME マクロの定義はというと、こちらは unicode/uvernum.h で定義されている。

unicode/uversion.h    Line 128~

#       define U_DEF_ICU_ENTRY_POINT_RENAME(x,y) x ## y
#       define U_DEF2_ICU_ENTRY_POINT_RENAME(x,y) U_DEF_ICU_ENTRY_POINT_RENAME(x,y)
#       define U_ICU_ENTRY_POINT_RENAME(x)    U_DEF2_ICU_ENTRY_POINT_RENAME(x,U_ICU_VERSION_SUFFIX)

ここで ## はトークン結合演算子で、x は 「icu」、U_ICU_VERSION_SUFFIXは「_69」など、_ + ライブラリのバージョンが入っている

unicode/uversion.h    Line 89

#define U_ICU_VERSION_SUFFIX _69

つまり「icu」は、「icu_69」のエイリアスである。

つまり

前方宣言で自分が定義した「namespace icu」というモノが既にあるのに、同じ「icu」をicu_69のエイリアスとして使おうとしたことになって、エラーが起こっている。

エラーの回避策

バージョンが固定でいいなら以下のように正規の名前空間で前方宣言すれば解決する

// クラスが名前空間に入っている時は前方宣言をこうする
namespace icu_69{
  class UnicodeString;
}

struct MyICU {
  icu_69::UnicodeString* ustr;
};

// ICUライブラリのUnicodeStringのラッパーを作成
MyICU make_my_icu(const char16_t* text);

しかしどうせ隠すなら素直にpimplとして完全に隠す方がいい。

余談

U_DISABLE_RENAMINGマクロを使えば解決しそうに見えるが、マニュアルには「内部処理用だから使うな」と書いてあるのであきらめる。

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: