Haskell の undefined や error が羨ましかったので, C++0x で作ってみた

http://ideone.com/nh39a

#include <stdexcept>
#include <utility>

namespace proto_etude // prototype etude
{
  // あらゆる型として評価できるが,実際に評価されると例外を投げる型
  struct undefined_t
  {
    // 任意の型への変換
    template< class T >
    operator T&&() const {
      throw std::logic_error( "etude::undefined must not be used!" );
    }
    
  };
  undefined_t const undefined = {};
  
  
  // 例外を投げる関数.
  // throw との違いは,戻り値をあらゆる型として評価できる点
  
  // 例外オブジェクトを指定して例外を投げる
  // error<std::runtime_error>( "はわわ ><" ); のように使う
  template< class Exception, class... Args >
  inline undefined_t error( Args&&... args )
  {
    throw Exception( std::forward<Args>(args)... );
  }
  
  // std::logic_error を投げる
  template< class What >
  inline undefined_t error( What && what ) {
    throw std::logic_error( std::forward<What>( what ) );
  }
  
  // デフォルトのエラーメッセージでエラーを投げる
  inline undefined_t error() {
    throw std::logic_error( "etude::error() must not be used!" );
  }
  
  // 本当は Haskell の error に相当する「 lazy なメッセージ指定つきエラー関数」を作りたかったが,
  // 面倒だったのでやめた. undefined を使えばいいし.
  
} // namespace proto_etude


// 使い道

// error の例として,単項 * 演算子をラップしてみる
template< class T >
inline T& dereference( T* p ) {
  return p ? *p : proto_etude::error( "ぬるぽ" ); // throw だとこうは書けない
}

#include <iostream>

int main()
{
  // undefined の一例
  constexpr int i = true ? 0 : proto_etude::undefined;  // 評価されなければエラーにならない
  std::cout <<  dereference(&i) << std::endl; // 0
  
  try {
    std::cout <<  dereference( (int*)0 ) << std::endl;
  }
  catch( std::logic_error& ) {
    std::cout << "OK.\n";
  }
}

注意事項としては void へは変換できない点ですが,その場合は

void f() {
  return (void)proto_etude::error();
}

ないし

void f() {
  return throw std::logic_error("にゃー><");
}

とでも書けばいいでしょう.


戻り値がテンプレートの場合には,

template< class R >
R f() {
  return static_cast<R>( proto_etude::error() );
}

で問題なし.


何にせよ, template operator T&&(); 万歳.
これを使えば,大抵の lazy 戦略は書けちゃうんじゃなイカ