Andy
Andy

Reputation: 137

Calling a generic lambda in boost::mpl::for_each()

A few answers here (How to loop through a boost::mpl::list? being the one I started with) imply that I should be able to construct a generic lambda to feed to a boost::mpl::for_each() but I'm unable to find a working example, or build one myself.

Idealy what I would like to be able to do in a lambda is take a function like

template<typename T>
void TestFunction(const int &p)
{
  T t(p);
  std::cout << "p = " << p << ", t = " << t << std::endl;
};

that I'm currently calling in a loop with something like

for(int k = 0; k < 2; ++k)
{
  TestFunction<int>(k);
  TestFunction<long>(k);
  TestFunction<float>(k);
  TestFunction<double>(k);
};

and replace it with something like

typedef boost::mpl::list<int, long, float, double> ValidTypes;

for(int k = 0; k < 2; ++k)
{
  // lambda definition that captures k

  // boost::mpl::for_each(ValidTypes, ...) that calls the lambda.
};

Is this possible? If not with for_each() with one of the other mpl constructs? I've got a version of the code running where I overload operator() but I'd like to see a lambda solution if it's possible.

Thanks, Andy.

Upvotes: 1

Views: 1824

Answers (1)

TemplateRex
TemplateRex

Reputation: 70556

If you can use C++14's generalized lambdas, you can capture the value of p and also infer the type of the current valid type being passed to the lambda:

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>

int main() 
{
    using ValidTypes = boost::mpl::list<int, long, float, double>;

    for (auto k = 0; k < 2; ++k) {
        boost::mpl::for_each<ValidTypes>([p = k](auto arg) { 
            using T = decltype(arg);
            T t(p);
            std::cout << "p = " << p << ", t = " << t << '\n'; 
        });
    }
}

Live Example.

Edit: for extra credit, here's a slightly more advanced version that also works for non-default constructible types:

#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>

class NonDefaultConstructible
{
    int value;
public:
    NonDefaultConstructible(int const& p) : value(p) {}

    friend auto& operator<<(std::ostream& ostr, NonDefaultConstructible const& ndc)
    {
        return ostr << ndc.value;
    }
};

int main() 
{
    using ValidTypes = boost::mpl::list<int, long, float, double, NonDefaultConstructible>;

    for (auto k = 0; k < 2; ++k) {
        boost::mpl::for_each<ValidTypes, boost::mpl::make_identity<boost::mpl::_1>>([p = k](auto arg) { 
            using T = typename decltype(arg)::type;
            T t(p);
            std::cout << "p = " << p << ", t = " << t << '\n'; 
        });
    }
}

Live Example.

For an explanation of the somewhat convoluted use of make_identity, see my very first Q&A here!

Upvotes: 1

Related Questions