Egg drop problem solution in template meta-programming
Template metaprogramming is all about rewriting your program to be functional instead of imperative, and then not worrying about caching since the compiler takes care of that for you. The other important guideline is that the return of a metafunction is a type named type. Template metaprogramming is about types - anything that isn't a type is just really annoying to have to deal with, so stay in the type world for as long as possible. 

So how do we write this functionally? Let's look at the loop - which is the only really interesting part of the code:

int result = INT_MAX;
for(int current_floor = 1; current_floor &lt;= floor; ++current_floor) {
    int local = std::max(solve(egg - 1, current_floor - 1), solve(egg, floor - current_floor));
    if(local &lt; result)
        result = local;
}


Rewriting this in Python as a generator comprehension (even if you don't know Python, hopefully this is clear):

result = 1 + min(
           max(solve(egg-1, current-1), solve(egg, floor-current))
           for current in range(1, floor+1)
           )


Going from 1 to floor is a little more awkward than going from 0 to floor-1, so let's just subtract 1 from current everywhere:

result = 1 + min(
           max(solve(egg-1, current), solve(egg, floor-current-1))
           for current in range(floor)
           )


Now, this is the right form for template metaprogramming! So what tools do we need to build this up?


A way to iterate from 0 to floor-1
A way to take the min and max of lots of things at compile time
A way to add one to a type


For the former, we have std::make_index_sequence and the latter two I will leave as an exercise. 

Once we have these things though, we directly translate the generator comprehension into actual template code thanks to the power of unpacking variadic templates:

template &lt;int Egg, int Floor, typename = std::make_index_sequence&lt;Floor&gt;&gt;
struct SolveImpl;

template &lt;int Egg, int Floor, size_t... Current&gt;
struct SolveImpl&lt;Egg, Floor, std::index_sequence&lt;Current...&gt;&gt;
{
    using type = add1&lt;                            // result = 1 +
        min&lt;                                      //   min(
            max&lt;                                  //     max(
                Solve&lt;Egg-1, Current&gt;,            //        solve(egg-1, current),
                Solve&lt;Egg, Floor - Current - 1&gt;   //        solve(egg, floor-current-1)
            &gt;...                                  //     ) for current in range(floor)
        &gt;                                         //  )
    &gt;;
};


Dealing with the base cases is just a matter of wrapping with std::conditional:

template &lt;int Egg, int Floor&gt;
struct Solve;

/* the SolveImpl code goes here */

template &lt;int Egg, int Floor&gt;
struct Solve
    : std::conditional_t&lt;
            (Floor == 0 || Floor == 1 || Egg == 1),
            int_&lt;Floor&gt;,
            SolveImpl&lt;Egg, Floor&gt;
            &gt;::type
{ };


Again, leaving out the base case details where Floor == 0, Floor == 1, or Egg == 1 since those are less interesting. As always, with template metaprograms, static_assert is your friend:

static_assert(Solve&lt;2, 10&gt;::value == 4, "!");


Check!