Search code examples
c++boost-mpl

choosing ctor arguments at runtime


Is it possible to address the following scenario of choosing the argument at runtime with mpl?

struct A {
    A(int number) { /* use number */ } };
struct B { };

template <typename T, int n>
struct A_or_B_Holder {
    A_or_B_Holder() : _t( /* void or 'n', depends on T */ ) { }
private:
    T _t;
};

A_or_B_Holder<B, void> b;
A_or_B_Holder<A, 3> a;

Ideally,

A_or_B_Holder<B> b;
A_or_B_Holder<A, 3> a;

Solution

  • Your first problem is that void is a type, not an integer. You could make the template accept two types, the second being either boost::mpl::int_ or void.

    Then you could either specialize the entire struct, or you could put the data member in a base class and specialize that.

    #include <boost/mpl/int.hpp>
    
    struct A {
        A(int number) { /* use number */ } };
    struct B { };
    
    template <class T, class Value>
    struct A_or_B_Holder_Base{
        A_or_B_Holder_Base(): _t(Value::value) {}
    protected:
        T _t;
    };
    
    template <class T>    
    struct A_or_B_Holder_Base<T, void> {
        A_or_B_Holder_Base(): _t() {}
    protected:
        T _t;
    };
    
    template <typename T, typename Value>
    struct A_or_B_Holder : public A_or_B_Holder_Base<T, Value> {
    
    };
    
    using boost::mpl::int_;
    A_or_B_Holder<A, int_<3> > x;
    A_or_B_Holder<B, void> y;
    A_or_B_Holder<A, void > w;  //error, no default constructor
    A_or_B_Holder<B, int_<3> > z;  //error, no int constructor
    

    More natural might be not to require the parameter to be a compile-time constant (as you are turning the compile-time constant into a run-time variable anyway). Just overload the constructor.

    struct A {
        A(int number) { /* use number */ } };
    struct B { };
    
    
    template <typename T>
    struct A_or_B_Holder {
        A_or_B_Holder() : _t( ) { }
        A_or_B_Holder(int number): _t(number) {}
    private:
        T _t;
    };
    
    A_or_B_Holder<B> b;
    A_or_B_Holder<A> a(3);