1. ホーム
  2. c++

[解決済み] ユーザー定義リテラルはC++にどのような機能を追加するのですか?

2022-05-13 14:21:27

質問

C++11 導入 ユーザー定義リテラル を導入し、既存のリテラルをベースにした新しいリテラルの構文が導入できるようになります ( int , hex , string , float など) を使って、どのような型でもリテラルな表現ができるようにします。

例を挙げます。

// imaginary numbers
std::complex<long double> operator "" _i(long double d) // cooked form
{ 
    return std::complex<long double>(0, d); 
}
auto val = 3.14_i; // val = complex<long double>(0, 3.14)

// binary values
int operator "" _B(const char*); // raw form
int answer = 101010_B; // answer = 42

// std::string
std::string operator "" _s(const char* str, size_t /*length*/) 
{ 
    return std::string(str); 
}

auto hi = "hello"_s + " world"; // + works, "hello"_s is a string not a pointer

// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

一見するととてもクールなのですが、果たしてどの程度応用が利くのか、接尾辞に _AD_BC は日付を作成する 演算子の順序の関係で問題があることがわかりました。 1974/01/06_AD は最初に 1974/01 (を評価します(プレーンな int のように)、そして後に初めて 06_AD (がない状態で8月と9月を書かなければならないのは言うまでもありません。 0 をつけずに書く必要があるのは言うまでもありません)。これを回避するには、構文を 1974-1/6_AD とすることで、演算子の評価順序が機能するように回避できますが、不格好です。

つまり、私の質問は、この機能自体が正当化されると感じますか?C++ コードをより読みやすくするために、他にどのようなリテラルを定義したいですか?


2011年6月の最終ドラフトに合わせて構文を更新しました。

どのように解決するのですか?

コンストラクタ呼び出しの代わりにユーザー定義リテラルを使用することに利点があるケースを紹介します。

#include <bitset>
#include <iostream>

template<char... Bits>
  struct checkbits
  {
    static const bool valid = false;
  };

template<char High, char... Bits>
  struct checkbits<High, Bits...>
  {
    static const bool valid = (High == '0' || High == '1')
                   && checkbits<Bits...>::valid;
  };

template<char High>
  struct checkbits<High>
  {
    static const bool valid = (High == '0' || High == '1');
  };

template<char... Bits>
  inline constexpr std::bitset<sizeof...(Bits)>
  operator"" _bits() noexcept
  {
    static_assert(checkbits<Bits...>::valid, "invalid digit in binary string");
    return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
  }

int
main()
{
  auto bits = 0101010101010101010101010101010101010101010101010101010101010101_bits;
  std::cout << bits << std::endl;
  std::cout << "size = " << bits.size() << std::endl;
  std::cout << "count = " << bits.count() << std::endl;
  std::cout << "value = " << bits.to_ullong() << std::endl;

  //  This triggers the static_assert at compile time.
  auto badbits = 2101010101010101010101010101010101010101010101010101010101010101_bits;

  //  This throws at run time.
  std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101_bits");
}

利点は、実行時例外がコンパイル時エラーに変換されることです。 文字列を取るbitset ctorに静的アサートは追加できませんでした(少なくとも文字列テンプレート引数なしには)。