Вопрос

Редактировать: Я отредактировал образец, чтобы он лучше напоминал мою проблему, теперь функция зависит от обычного параметра (а не только от параметров шаблона), что означает, что вычисления не мочь быть сделано во время компиляции.


Я написал код, написанный от руки список типов и теперь мы начали использовать способствовать росту и я пытаюсь переместить его в mpl библиотека.

Кажется, я не могу найти достойную документацию для mpl::list и мне даже не удается перенести код на boost::mpl.У меня такое ощущение, что даже когда (если?) мне удастся портировать код, он все равно не будет идиоматическим.Не могли бы вы сообщить мне, как следует написать следующее с помощью boost (обратите внимание, что это не настоящий код, а надуманное упрощение).

Исходный код (вставить codepad.org)

class nil {};

template <class Head, class Tail = nil>
struct type_list {
    typedef Head head;
    typedef Tail tail;
};

template <class List>
struct foo;

template <class Head, class Tail>
struct foo<type_list<Head, Tail> >{
    template <class T>
    static void* bar(T* obj, size_t size)
    {
        if (sizeof(Head) == size) 
            return reinterpret_cast<Head*>(obj);

        // Otherwise check the rest of the list
        return foo<Tail>::bar(obj, size);
    }
};


template <>
struct foo<nil>
{
    template <class T>
    static void* bar(T*, size_t)  { return NULL; }
};

#include <iostream>

int main()
{
    int n = 3;
    void *p = foo<type_list<char, type_list<bool, 
                      type_list<double, type_list<long> > > >
                 >::bar(&n, 4); 
    std::cout<< p << std::endl;
}

Неудачная попытка использовать Boost (вставить codepad.org)

#include <boost/mpl/list.hpp>

template <class List>
struct foo{
    template <class T>
    static void* bar(T* obj, size_t size)
    {
        typedef typename boost::mpl::front<List>::type type;
        if (sizeof(type) == size) 
            return reinterpret_cast<type*>(obj);

        // Otherwise check the rest of the list
    return foo<typename List::next>::bar(obj, size);
  }
};

template <>
struct foo<boost::mpl::list0<boost::mpl::na> >
{
    template <class T>
    static void* bar(T*)
    {
        return NULL;
    }
};

#include <iostream>

int main()
{
    int n = 3;
    void *p = foo<boost::mpl::list<char, bool, double, long> >::bar(&n, 4);
    std::cout << p << std::endl;
}
Это было полезно?

Решение

Использовать boost::mpl::fold так:

#include <boost/mpl/list.hpp>
#include <boost/mpl/fold.hpp>

#include <iostream>

using namespace boost::mpl;

// Initial state:
struct foo_start {
    template <typename T>
    static void * bar( T *, size_t ) { return 0; }
};

// Folding Step: add This to Prev
template <typename Prev, typename This>
struct foo_iteration {
    struct type {
        template <typename T>
        static void * bar( T * obj, size_t size ) {
            if ( sizeof(This) == size )
                return reinterpret_cast<This*>(obj);
            else
                return Prev::bar( obj, size );
        }
    };
};

// foo is just calling mpl::fold now:
template <typename List>
struct foo : fold< List, foo_start, foo_iteration<_,_> >::type {};

int main() {
    int n = 3;
    void * p = foo< list<char, bool, double, long> >::bar( &n, 4 );
    std::cout << p << std::endl;
}

Принты 0 здесь, но у меня amd64, поэтому мне нужно изменить 4 для 8, и получить что-то ненулевое.

ХТХ

Другие советы

MPL плохо подходит для смешанных операций времени компиляции и выполнения.

Единственная операция, разрешенная во время выполнения последовательностей MPL, — это «for_each».Во всех остальных ситуациях вам следует сделать бросок самостоятельно.

Поэтому вам следует учитывать, что типы MPL не предназначены для создания экземпляров.

Однако в Boost есть и другие возможности для этого.

Старый:Boost.Tuple

Новый:Boost.Fusion > http://spirit.sourceforge.net/dl_more/fusion_v2/libs/fusion/doc/html/index.html

Boost.Fusion немного сложнее (например, он объединяет концепцию представлений), но гораздо лучше подходит для вашего примера.

Это не значит, что вам не следует использовать MPL.Напротив, в справочном документе Boost.Fusion явно указано, что следует использовать алгоритмы MPL для вычислений во время компиляции, а затем собирать контейнер Boost.Fusion только в тот момент, когда вы пересекаете границу времени компиляции/время выполнения (даже хотя контейнер Boost.Fusion должен работать с алгоритмами MPL).

Итак, продолжайте свою реализацию mpl, преобразуйте полученный список в последовательность Boost.Fusion.Затем создайте экземпляр последовательности и используйте все возможности Boost.Fusion.

Предупреждение:давно не занимался C++ (метапрограммированием, если уж на то пошло), так что могу ошибаться.

Если я правильно понимаю, ваш исходный код находит первый тип, который имеет тот же размер, что и переданный аргумент, и приводит аргумент к этому типу.Предполагая, что реализация его с помощью mpl в основном сводится к использованию найти_если алгоритм с собственным написанным предикатом для проверки размера типа (см. пример по ссылке выше).Только typedef результат, примените его, и все готово.

Если я правильно понимаю, вы передаете T во время выполнения и надеетесь, что ваш список MPL {A, B, C, D} выберет правильный T в этом наборе и будет действовать в соответствии с ним?

Возможно, я ошибаюсь, но это похоже на Boost.Fusion, который предназначен для итерации последовательностей во время компиляции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top