Boost.Initialized で、宣言時に初期値を設定する

Boost.Initialized といいつつ、ほぼオレオレ Initialized になっていますが……。
Boost.Initialized は初期化のみで、初期値を設定することが出来ないので出来るようにしてみました。
基本的な動作は、Boost.Initialized と同じです。


[サンプルソース]

#include <iostream>
#include <string>
#include <boost/mpl/divides.hpp>

template<typename T, typename Initializer = void>
struct initialized;

namespace mpl = boost::mpl;

template<typename T1, typename T2>
struct divides : mpl::divides<T1, T2>{
    template<typename T>
    operator T() const{
        return static_cast<T>(static_cast<T>(T1::value) / static_cast<T>(T2::value));
    }
};
typedef divides<mpl::int_<355>, mpl::int_<113> > PI;  // 355/113 で PI の近似値

// 実行時に計算したくなければこんな感じ。
// struct PI{
//     operator float() const{
//         return 3.14f;
//     }
// };

template<typename Seq>
struct c_str : mpl::c_str<Seq>{
    typedef typename Seq::value_type const* value_type;
    operator value_type() const{
        return mpl::c_str<Seq>::value;
    };
};

struct init_hello_world{
    typedef std::string value_type;
    operator value_type() const{
        return "hello world";
    }
};

struct check{
    initialized<int>              value1;  // int
    initialized<mpl::int_<10> >   value2;  // 10 で初期化
    initialized<mpl::true_>       value3;  // 型がなくても OK
    initialized<float, PI>        value4;  // 実数も渡せる
    initialized<init_hello_world> value5;  // ユーザ側で定義した値で初期化
    initialized<                           // MPL.String で文字列型も初期化
        std::string, c_str<mpl::string<'piyo'> > 
    > value6;
};

int
main(){
    check c;
    
    std::cout << c.value1 << std::endl;
    std::cout << c.value2 << std::endl;
    std::cout << c.value3 << std::endl;
    std::cout << c.value4 << std::endl;
    std::cout << c.value5.data() << std::endl;
    std::cout << c.value6.data() << std::endl;
    
    return 0;
}

[出力]

0
10
1
3.14159
hello world
piyo


変数宣言をする際に Initializer を渡すことで、Initializer に定義されている設定で初期化を行います。
Initializer がなければ、Boost.Initialized と同様にデフォルト値で初期化が行われます。
Initializer は、T型へのキャストが書かれていればなんでもいいです。
value_type が定義されているならば T に直接 Initializer を渡してしまっても構いません。
Boost.MPL の Integral Constant をそのまま初期値として設定できます。
string も MPL.String を使用しようして初期化を行うことが出来ます。


って、感じで、とりあえず、つくってみました。
Boost.Initialized 全然使わないのにねー……。
あと C++0x はガン無視。
constexpr の辺りと組み合わせるとどうなんでしょうか。


[boost]
ver 1.46.1
[参照]
http://www.boost.org/doc/libs/1_46_1/libs/mpl/doc/refmanual/integral-constant.html


全てのソースはイカ

#include <boost/utility/value_init.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/has_xxx.hpp>


namespace detail{

namespace mpl = boost::mpl;

template<typename T, typename Initializer, typename sfinae = void>
struct initialized_impl : boost::initialized<T>{
    typedef boost::initialized<T> base_type;
    initialized_impl() : base_type(){}
    explicit initialized_impl(T const& arg) : base_type(arg){}
};

// Initializer が void 以外の場合
template<typename T, typename Initializer>
struct initialized_impl<T, Initializer, 
    typename boost::disable_if< boost::is_void<Initializer> >::type >
    : boost::initialized<T>{
    typedef boost::initialized<T> base_type;
    initialized_impl() : 
        base_type(static_cast<T>(Initializer())){}
    explicit initialized_impl(T const& arg) : base_type(arg){}
};

BOOST_MPL_HAS_XXX_TRAIT_DEF(value_type);

// T::value_type があり、Initializer が void の場合
template<typename T>
struct initialized_impl<T, void, typename boost::enable_if<has_value_type<T> >::type >
    : boost::initialized<typename T::value_type>{
    typedef boost::initialized<typename T::value_type> base_type;
    initialized_impl() : 
        base_type(static_cast<typename T::value_type>(T())){}
    explicit initialized_impl(T const& arg) : base_type(arg){}
};

}  // namespace detail

template<typename T, typename Initializer = void>
struct initialized : detail::initialized_impl<T, Initializer>{
    typedef detail::initialized_impl<T, Initializer> base_type;
    initialized() : base_type(){}
    explicit initialized(T const& arg) : base_type(arg){}
};


#include <iostream>
#include <string>
#include <boost/mpl/divides.hpp>
#include <boost/mpl/string.hpp>

namespace mpl = boost::mpl;

template<typename T1, typename T2>
struct divides : mpl::divides<T1, T2>{
    template<typename T>
    operator T() const{
        return static_cast<T>(static_cast<T>(T1::value) / static_cast<T>(T2::value));
    }
};
typedef divides<mpl::int_<355>, mpl::int_<113> > PI;

// struct PI{
//     operator float() const{
//         return 3.14f;
//     }
// };
 
template<typename Seq>
struct c_str : mpl::c_str<Seq>{
    typedef typename Seq::value_type const* value_type;
    operator value_type() const{
        return mpl::c_str<Seq>::value;
    };
};

struct init_hello_world{
    typedef std::string value_type;
    operator value_type() const{
        return "hello world";
    }
};

struct check{
    initialized<int>              value1;
    initialized<mpl::int_<10> >   value2;
    initialized<mpl::true_>       value3;
    initialized<float, PI>        value4;
    initialized<init_hello_world> value5;
    initialized<
        std::string, c_str<mpl::string<'piyo'> > 
    > value6;
};

int
main(){
    check c;
    
    std::cout << c.value1 << std::endl;
    std::cout << c.value2 << std::endl;
    std::cout << c.value3 << std::endl;
    std::cout << c.value4 << std::endl;
    std::cout << c.value5.data() << std::endl;
    std::cout << c.value6.data() << std::endl;
    
    return 0;
}