edouarda / brigand

Instant compile time C++ 11 metaprogramming library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Help with a simple example

atom-moyer opened this issue · comments

Hi all,

This is my first attempt at metaprogramming, so I am a total novice.

Right now, I am attempting to wrap a high performance hash table written in C++ and bind it to python/numpy. This requires that I create compiled version of all combinations of supported Key:Value pair types. A perfect place for metaprogramming I thought, compared to writing a python script that generates all of the typedef lines.

However I am having issues due to the lack of documentation or understanding I believe. Here is my current code which does not work because I am making hash tables of type: _Dict<brigand::type_<TYPE>, brigand::type_<TYPE>> instead of _Dict<TYPE, TYPE>. Therefore, I am getting errors like: error: no match for call to ‘(std::hash<brigand::type_<int> >).

Here is my current program:

(Note: I also have a class of _Dict<Key, Value> implemented which I can compile with explicit types.)

#include <pybind11/pybind11.h>

namespace py = pybind11;

#include <brigand/brigand.hpp>
#include <brigand/sequences/list.hpp>
#include <brigand/algorithms/for_each.hpp>

using types = brigand::list<
    float, int
>;

template<typename Key, typename Value>
void declare_Dict(const py::module& m) {
    using Class = _Dict<Key, Value>;
    
    std::string name = std::string("_Dict_") + typeid(Key).name() + std::string("_") + typeid(Value).name();

    py::class_<Class>(m, name.c_str())
        .def(py::init<>())
        .def("__getitem__", &Class::__getitem__)
        .def("__setitem__", &Class::__setitem__)
        .def("__delitem__", &Class::__delitem__)
        .def("__contains__", &Class::__contains__)
        .def("__len__", &Class::__len__);
}

PYBIND11_MODULE(_sparsepy, m) {
    m.doc() = "Fast and Memory Efficient Sparse Hash Tables for Python"; 

    brigand::for_each<types>([&m](auto key) {
        brigand::for_each<types>([&m, key](auto value) {
            declare_Dict<key, value>(m);
        });
    });
}

Does anyone know how I can get the template type of Brigand::type_? Am I doing something else wrong? Doing only one for loop at a time and "locking" one of types does not help with the errors, so the nested for_each does not seem to be the issue.

Thanks!
Adam

Hi

the type_ is here so you can apply for_each on any type, including void.
You can use the inside type by using ::type as shown here :

https://github.com/edouarda/brigand/blob/master/include/brigand/types/type.hpp

So you code should be :

brigand::for_each<types>([&m](auto key) {
        brigand::for_each<types>([&m, key](auto value) {
            using key_type = std::decay_t<decltype(key)>::type;
            using value_type = std::decay_t<decltype(value)>::type;
            declare_Dict<key_type, value_type>(m);
        });
    });

The decltype retrieve the type of key and value. decay_t ensures there is no const or & on the type before accessing the inner ::type. If you use C++20, using template lambda remove the need for this decay/decltype dance.

Tell us if it fixes your issue.

Thank you very much!

This works exactly as expected.