выбор аргументов ctor во время выполнения - PullRequest
0 голосов
/ 31 августа 2011

Можно ли обратиться к следующему сценарию выбора аргумента во время выполнения с помощью 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;

В идеале

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

Ответы [ 3 ]

1 голос
/ 31 августа 2011

Ваша первая проблема в том, что void - это тип, а не целое число.Вы можете заставить шаблон принимать два типа, вторым является либо boost::mpl::int_ или void.

Затем вы можете либо специализировать всю структуру, либо вы можете поместить элемент данных в базовый класс и специализировать это..

#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

Более естественным может быть не требовать, чтобы параметр был константой времени компиляции (так как в любом случае вы превращаете постоянную времени компиляции в переменную времени выполнения).Просто перегрузите конструктор.

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);
0 голосов
/ 31 августа 2011

Вы можете использовать Boost.Variant

#include <boost/variant.hpp>

struct A
{
};

struct B
{
    B(int)
    {
    }
};

int main()
{
    boost::variant<A, B> val;

    if (/*some condition*/)
    {
        val = A();
    }
    else
    {
        val = B(5);
    }
}

Если вас больше интересует, как это реализовано, чем то, что вы можете использовать, я предлагаю вам проверить реализацииBoost.Any и Boost.Variant.

0 голосов
/ 31 августа 2011

Я думаю, что передача различных аргументов во время выполнения невозможна. У вас должен быть стандартный конструктор, который будет у всех типов T. Вы можете сделать все типы T конструкцией из std::vector<void*> и использовать это для передачи переменного числа аргументов переменного типа, но это super опасно.

Тем не менее, кажется, что ваш образец действительно принимает решение во время компиляции, а не во время выполнения, что решаемо.

const int NO_INT_PARAM=INT_MIN;
template <typename T, int n>
struct A_or_B_Base {
    A_or_B_Holder() : _t(n) { }
private:
    T _t;
};
template <typename T>
struct A_or_B_Base<T, NO_INT_PARAM> {
    A_or_B_Holder() : _t() { }
private:
    T _t;
};
template <typename T, int n=NO_INT_PARAM>
struct A_or_B_Holder : A_or_B_Base<T, n>{
    A_or_B_Holder() : A_or_B_Base() { }
    /* other functions*/
};

A_or_B_Holder<A, 3> a; //uses A(3) constructor
A_or_B_Holder<B> b;  //uses B() constructor
A_or_B_Holder<A> c; //compiler error! A() doesn't exist!
A_or_B_Holder<B, 5> d;  //compiler error! B(5) doesn't exist!
A_or_B_Holder<B, NO_INT_PARAM> e;  //same as b, uses B() constructor
...