char8_t 欲しい

C++0x からは UTF16 の文字列リテラル(u"...")とその型(char16_t)、UTF32 の文字列リテラル(U"...")とその型(char32_t)が入ります。
そして UTF8 の文字列リテラル(u8"...")も入ります。しかし UTF8 を表す型は入りません。u8"..." は char の配列を返します。
ある関数の引数が "..." と u8"..." のどちらで渡されたのかを区別する方法はありません。残念です。
まあ今更入れろなんて言ったところでどうせ無理だと思うので、諦めて何かうまい方法を探しましょうということで、適当に考えてみました。

struct char8_t {
    // いろいろ実装
};
const char8_t* u8(const char* str) {
    return reinterpret_cast<const char8_t*>(str);
}
#define u8(s) u8(u8 ## s)

適当に UTF8 用の型を作って、その文字列リテラルを作る関数を用意して、便利に使えるマクロを用意してるだけですね。
こんな感じで使います。

void f(const char8_t* str);
f("hoge"); // コンパイルエラー
f(u8("hoge")); // OK
f(u8"hoge"); // 残念ながらコンパイルエラー

ほんとは u8 関数は char の配列を受け取って char8_t の配列の rvalue を返す関数にしないといけない気がするのですがそんなことが可能なのかよく分からなくて調べてる途中でめんどくなったので諦めました。


マクロ死ねって人は頑張って u8(u8"...") と書きましょう。その場合、間違って u8("...") と書いたらアウトなので気をつけましょう。


追記:
char8_t 配列の rvalue を返す関数を iorate 先生が書いてくれました。

こうかなあ。配列へのrv-refで。http://ideone.com/Af5Xi

Twitter. It's what's happening.
#include <cstddef>
#include <iostream>
#include <utility>
 
struct char8_t { char base; };
 
template <std::size_t N>
char8_t const (&&u8(char const (&s)[N]))[N]
{
    return std::move(*reinterpret_cast<char8_t const (*)[N]>(&s));
}
 
#define u8(s) u8(u8 ## s)
 
void print(char8_t const *s)
{
    while (s->base) {
        std::cout << s->base;
        ++s;
    }
}
 
int main()
{
    print(u8("Hello, world!"));
}

やばいですね。