funnyクラスを作ってみた。その1
boostのfunctionとanyを合わせたようなクラスを作ってみた。
対応コンパイラは、VCとGCCのみ。
variadic templatesの使用推奨。
簡単な使用例。
#include <iostream> #include <cstdlib> #include "funny.h" int main() { funny<> x; x = 1; std::cout << (int)x << std::endl; x = 3.1415; std::cout << (double)x << std::endl; funny<func<double(const char*)>::type> f = &std::atof; std::cout << f("1.2345") << std::endl; return 0; }
以下実装。
// funny.h #if defined(_MSC_VER) #pragma warning(disable:4250) #endif #include <typeinfo> #include <stdexcept> #include <algorithm> #ifdef __GXX_EXPERIMENTAL_CXX0X__ #define VT #endif template <class T> struct remove_const { typedef T type; }; template <class T> struct remove_const<const T> { typedef T type; }; class bad_call:public std::exception{}; template <class T,class U,class V,class W> struct any_type; class null_type{}; #ifdef VT #define ___ ... #else #define ___ #endif #ifdef VT template <class D, class B, class V, class W, template<class,class,class,class>class ... T> class IMPS; template <class D, class B,class V, class W> class IMPS<D,B,V,W>:public any_type<D,B,V,W>{}; template <class D, class B,class V, class W, template<class,class,class,class>class T> class IMPS<D,B,V,W,T>:public T<D,B,V,W>{}; template <class D, class B,class V, class W, template<class,class,class,class>class T, template<class,class,class,class>class ... U> class IMPS<D,B,V,W,T,U ...>:public IMPS<D,IMPS<D,B,V,W,T>,V,W,U ...>{}; #else template <class D, class B,class V, class W, template<class,class,class,class>class T> class IMPS:public T<D,B,V,W>{}; #endif #ifdef VT template <template <class,class,class,class>class ... T> #else template <template <class,class,class,class>class T=any_type> #endif class funny:public IMPS<funny<T ___>,null_type,funny<T ___>,funny<T ___>,T ___> { public: class funny_imp_base:public T<funny,null_type,funny,funny>::interface ___ { public: virtual funny_imp_base* create() const=0; virtual const std::type_info& type() const = 0; }; private: template <class S> class funny_imp:public IMPS<funny_imp<S>,funny_imp_base,funny_imp_base,funny, T ___> { template <template<class,class,class,class> class ___ U> friend class funny; public: funny_imp(const S& x): data_(x){} funny_imp* create() const { return new funny_imp(data_); } const std::type_info& type() const { return typeid(S); } void typecheck(const funny_imp_base&) const { } const S* data() const { return &data_; } S* data() { return &data_; } private: S data_; }; public: funny():data_(){} template <class U> funny(const U& x): data_(new funny_imp<U>(x)){} template <class U> funny& operator=(const U& x) { delete data_;data_ = new funny_imp<U>(x); return *this; } funny& operator=(const funny& x) { if(this != &x) { funny tmp(x); swap(tmp); } return *this; } funny(const funny& x) { if(x.data_) data_ = x.data_->create(); else data_ = 0; } template <class U> operator const U&() const { if(funny_imp<U>* p = dynamic_cast<funny_imp<U>*>(data_)) return *p->data(); throw std::bad_cast(); } template <class U> operator U&() { if(funny_imp<typename remove_const<U>::type>* p = dynamic_cast<funny_imp<typename remove_const<U>::type>*>(data_)) return *const_cast<U*>(p->data()); throw std::bad_cast(); } ~funny(){delete data_;} void swap(funny& x) { std::swap(data_, x.data_); } bool empty() const { return !data_; } void clear() { delete data_; data_ = 0; } const std::type_info& type() const { if(!data_) return typeid(void); return data_->type(); } void typecheck(const funny& x) const { if(type() != x.type()) throw bad_call(); } funny_imp_base* data() const { if(!data_) throw bad_call(); return data_; } private: funny_imp_base* data_; }; template <class T,class U,class V,class W> struct any_type:public U { struct interface{}; }; template <class T> class func; template <class R, class ___ A> class func<R(A ___)> { #ifdef VT template <int N, class... S> struct GET { typedef void type; }; template <class S, class... U> struct GET<1,S,U...> { typedef S type; }; template <int N, class S, class... U> struct GET<N,S,U...> { typedef typename GET<N-1,U...>::type type; }; #endif public: template <class T, class U,class V,class W> class type:public U { public: typedef R result_type; #ifndef VT typedef A argument_type; #else template <int N> struct argument{ typedef typename GET<N,A...>::type type; }; typedef typename argument<1>::type argument_type; typedef typename argument<1>::type first_argument_type; typedef typename argument<2>::type second_argument_type; #endif R operator() (A ___ x) const { return (*static_cast<const T*>(this)->data())(x ___); } struct interface { virtual R operator()(A ___) const=0; }; }; };