読者です 読者をやめる 読者になる 読者になる

とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

文字列リテラルのラッパー string_literal クラステンプレート書いた

C++

追記: 2010-10-13 Update. operator= と swap 追加。
追記: 2010-10-08 Update. 規格書読んで std::string の仕様に近づけました。
車輪の再発明というか,range 使えって感じですが,練習でもあるので気にせず。
このように使えます。

#include<algorithm>
#include<iostream>
#include<sscrisk/string_literal.hpp>

int main()
{
 using namespace sscrisk;
 using namespace std;

 string_literal<> a("abc"); // 文字列リテラル
 string_literal<> b(a); // コピー
 string_literal<> const c(""); // 長さ0の文字列

 // 代入
 b = c;
 b = "ABC";

 // begin/end, cbegin/cend, rbegin/rend, crbegin/crend
 // 常に const なオブジェクトなので const をはずすとエラー
 for_each(a.begin(), a.end(), [](char const & c){
  std::cout << c;
 });
 cout << endl;
 for_each(b.crbegin(), b.crend(), [](char const & c){
  std::cout << c;
 });
 cout << endl;

 // size, length, empty
 cout << a.size() << ' ' << b.size() << ' ' << c.size() << endl;
 cout << a.length() << ' ' << b.length() << ' ' << c.length() << endl;
 cout << a.empty() << ' ' << b.empty() << ' ' << c.empty() << endl;

 // operator[], at
 cout << a[0] << endl;
 try
 {
  cout << a.at(3) << endl; // at 範囲外は例外投げる
 }
 catch(exception const & e)
 {
  cout << e.what() << endl;
 }

 // c_str, data, make_string_literal, substr, operator<<
 cout << a.c_str() << endl;
 cout << b.data() << endl;
 cout << make_string_literal("abcde").substr(1).substr(2) << endl;

 // swap
 swap(a, b);
 cout << a << endl << b << endl;
}

実行結果

abc
CBA
3 3 0
3 3 0
0 0 1
a
string_literal<>::at : out of range exception
abc
ABC
de
ABC
abc

ライブラリ側のソースはこちら

#if !defined(SSCRISK_STRING_LITERAL_HPP)
#define SSCRISK_STRING_LITERAL_HPP
#if defined(_MSC_VER) && _MSC_VER >= 1020
#pragma once
#endif

// string_literal.hpp

#include<string>
#include<cstddef>
#include<iterator>
#include<stdexcept>
#include<utility>
#include<iosfwd>

namespace sscrisk{

 template<class charT = char, class traits = std::char_traits<charT>>
 class string_literal
 {
 public:
  typedef traits traits_type;
  typedef typename traits::char_type value_type;
  typedef void allocator_type; // not support
  typedef std::size_t size_type;
  typedef std::ptrdiff_t difference_type;

  typedef charT& reference;
  typedef charT const & const_reference;
  typedef charT* pointer;
  typedef charT const * const_pointer;

  typedef void iterator; // not support
  typedef charT const * const_iterator;
  typedef void reverse_iterator; // not support
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

 private:
  charT const * p;
  size_type len;

 public:
  string_literal(string_literal const & sl)
   : p(sl.p), len(sl.len)
  {}
  template<std::size_t n>
  string_literal(charT const (& s)[n], size_type pos = 0)
   : p(s + pos), len(n - pos - 1)
  {
   if(pos > size())
    throw std::out_of_range(
    "string_literal<>::string_literal : out of range exception");
  }
  string_literal& operator=(string_literal const & sl)
  {
   p = sl.p;
   len = sl.len;
   return *this;
  }
  template<std::size_t n>
  string_literal& operator=(charT const (& s)[n])
  {
   p = s;
   len = n - 1;
   return *this;
  }

  const_iterator begin()const
  {
   return p;
  }
  const_iterator end()const
  {
   return p + len;
  }

  const_reverse_iterator rbegin()const
  {
   return const_reverse_iterator(end());
  }
  const_reverse_iterator rend()const
  {
   return const_reverse_iterator(begin());
  }

  const_iterator cbegin()const
  {
   return p;
  }
  const_iterator cend()const
  {
   return p + len;
  }
  const_reverse_iterator crbegin()const
  {
   return const_reverse_iterator(cend());
  }
  const_reverse_iterator crend()const
  {
   return const_reverse_iterator(cbegin());
  }

  size_type size()const
  {
   return len;
  }
  size_type length()const
  {
   return size();
  }
  bool empty()const
  {
   return size() == 0;
  }
  
  const_reference operator[](size_type pos)const
  {
   return p[pos];
  }
  const_reference at(size_type pos)const
  {
   if(pos >= size())
    throw std::out_of_range("string_literal<>::at : out of range exception");
   return operator[](pos);
  }

  void swap(string_literal& s)
  {
   std::swap(p, s.p);
   std::swap(len, s.len);
  }

  charT const * c_str()const
  {
   return p;
  }
  charT const * data()const
  {
   return c_str();
  }

  string_literal substr(size_type pos = 0)const
  {
   if(pos > size())
    throw std::out_of_range(
    "string_literal<>::substr : out of range exception");
   return string_literal<charT>(data() + pos, size() - pos);
  }
  private:
   string_literal(charT const * s, size_type n)
    : p(s), len(n)
   {}
 };

 template<class charT, class traits>
 void swap(string_literal<charT, traits>& lhs,
  string_literal<charT, traits>& rhs)
 {
  lhs.swap(rhs);
 }

 template<class charT>
 std::ostream& operator<<(std::ostream& os, string_literal<charT> const & sl)
 {
  return os << sl.c_str();
 }

 template<class charT, std::size_t n>
 string_literal<charT> make_string_literal(charT const (& str)[n])
 {
  return string_literal<charT>(str);
 }

}

#endif

問題,改善点あったら教えてください。