1

I'm trying to port this answer: Replace N formulas to one (string interpolation) to a standard c++98 implementation.

C++14 version:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <string>

using namespace std;

int main() {
    map<string, string> interpolate = { { "F"s, "a && b && c"s }, { "H"s, "p ^ 2 + w"s }, { "K"s, "H > 10 || e < 5"s }, { "J"s, "F && !K"s } };

    for(const auto& i : interpolate) for_each(begin(interpolate), end(interpolate), [&](auto& it){ for(auto pos = it.second.find(i.first); pos != string::npos; pos = it.second.find(i.first, pos)) it.second.replace(pos, i.first.size(), '(' + i.second + ')'); });

    for(const auto& i : interpolate) cout << i.first << " : " << i.second << endl;
}

C++98: Making the map:

std::map<std::string, std::string> interpolate_map;
interpolate_map.insert(std::make_pair("F", "a && b && c" ));
interpolate_map.insert(std::make_pair("H", "p ^ 2 + w" ));
interpolate_map.insert(std::make_pair("K", "H > 10 || e < 5" ));
interpolate_map.insert(std::make_pair("J", "F && !K" ));

for (const std::pair<const std::string, std::string> & i : interpolate_map)
/* ??? */

It's unclear to me how to proceed.

Anna K.
  • 95
  • 10
  • 2
    Convert the lambda to a functor. – NathanOliver Jun 19 '17 at 18:57
  • 1
    I've posted a [map_init](https://stackoverflow.com/questions/207976/how-to-easily-map-c-enums-to-strings/208003#208003) helper before. Even C++98 can be made readable by a reasonable dose of helper code. – MSalters Jun 20 '17 at 14:15

1 Answers1

1

There's a lot of involved in that, whoever wrote it really knows his stuff.

The code that you're looking at uses a style for-loop, a for_each-loop, and a traditional for-loop to effectively do three things:

  1. Loop through all the keys that could be interpolated
  2. Loop through all the value strings to interpolate
  3. Loop through the entire string to interpolate all keys

In your best bet is likely just a triple nested for-loop:

for(map<string, string>::iterator i = interpolate.begin(); i != interpolate.end(); ++i) {
    for(map<string, string>::iterator it = interpolate.begin(); it != interpolate.end(); ++it) {
        for(string::size_type pos = it->second.find(i->first); pos != string::npos; pos = it->second.find(i->first, pos)) {
            it->second.replace(pos, i->first.size(), '(' + i->second + ')');
        }
    }
}

Live Example

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 1
    It works except from the live demo (in my compiler) because the map can't be initialized like that (I used the initialization like I have it in the question instead). Kudos Mr Mee. – Anna K. Jun 19 '17 at 19:58
  • @AnnaK. You should be allowed to brace initialize a `map` but if your compiler is being ornery the `insert` method works. – Jonathan Mee Jun 19 '17 at 20:04
  • 1
    I get this: error: in C++98 ‘interpolate’ must be initialized by constructor, not by ‘{...}’ and warning: extended initializer lists only available with -std=c++11 or -std=gnu++11 – Anna K. Jun 19 '17 at 20:06
  • 1
    @AnnaK. You are correct on the initialization it seems, I thought that gcc6.3 defaulted to C++03 without a flag, turns out it defaults to C++14. Thus I'm really using `map`'s `initializer_list` constructor, which of you correctly surmise is *not* available in C++98: https://stackoverflow.com/q/44654713/2642059 – Jonathan Mee Jun 20 '17 at 14:28