// vector of pairs
vector<pair<regex, void (*)(string)>> patterns;
// store a regex pattern
patterns[0].first = pattern;
// store a function name
patterns[0].second = func1;
patterns[1].first = pattern2;
patterns[1].second = func2;
// take user's input
string input;
cin >> input;
for (int i = 0; i < patterns.size(); i )
{
if (regex_match(input, patterns[i].first)) // if the input matches one of the patterns, call the function associated with that pattern
{
patterns[i].second(input);
}
}
The problem is that I'm getting an error message for patterns[i].second(input);
saying that: the expression preceding parentheses of apparent call must have (pointer-to-) function type
CodePudding user response:
I would do it this way, so that the code also becomes a bit more self explaining :
#include <iostream>
#include <vector>
#include <string>
#include <regex>
#include <functional>
// using namespace std; <== NO
using handler_function_t = std::function<void(const std::string&)>;
// do not use pair, so hard to reason back to WHAT you mean
// define a struct
struct pattern_handler_t
{
pattern_handler_t(std::string&& rx, handler_function_t&& fn) :
regular_expression{ rx },
call{ fn }
{
};
const std::regex regular_expression; // give clear readable names, so much better then 'first' of pair
const std::function<void(const std::string&)> call;
};
void callback1(const std::string& text)
{
std::cout << text << ", starts with an a\n";
}
void callback2(const std::string& text)
{
std::cout << text << ", starts with a b\n";
}
int main()
{
// you can use an initializer list.
std::vector<pattern_handler_t> pattern_handlers
{
{"a.*",callback1},
{"b.*",callback2}
};
std::string input{ "another example" };
//std::cin >> input;
// use range based for loop for vector
for (const auto& pattern_handler : pattern_handlers)
{
std::smatch match;
if (std::regex_match(input, match, pattern_handler.regular_expression))
{
pattern_handler.call(match[0]);
}
}
return 0;
}
CodePudding user response:
Let us first look at your code: I will show you the problems and how to fix it. And then I will show, how it could be optimized further.
I will put comments in your code to show the problems:
// vector of pairs
// *** Here we have the base for a later problem
// *** After this line, you will have an empty vector, that has no elements.
vector<pair<regex, void (*)(string)>> patterns;
// *** The vector is empty.
// *** And if you try to access patterns[0] or patterns[1]
// *** then you try to acess elements that don't exist.
// *** This will cause UB (Undefined Behaviour)
// store a regex pattern patterns
patterns[0].first = pattern;
// store a function name
patterns[0].second = func1;
patterns[1].first = pattern2;
patterns[1].second = func2;
// *** all UB (Undefined Behaviour) from here on.
// take user's input
//*** Please use getline to read a complete line
string input;
cin >> input;
for (int i = 0; i < patterns.size(); i )
{
if (regex_match(input, patterns[i].first)) // if the input matches one of the patterns, call the function associated with that pattern
{
patterns[i].second(input);
}
}
So, obviously, you want to have a std::vector
with 2 elements, so that you can use the index operator to fill it.
With that the easiest way will be to use std::vectors
constructor no. 4 to set aninitial size. This could be done like this:
std::vector <std::pair <std::regex, void (*)(std::string&)>> patterns(2);
Then your could use the index operator []
to assign values.
But most likely, you would use either the std::vectors
push_back - function, or an initializer list.
So, an intermediate optimized solution could look like:
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <regex>
void function1(std::string& s) {
std::cout << "Function 1:\t " << s << '\n';
}
void function2(std::string& s) {
std::cout << "Function 2:\t " << s << '\n';
}
int main() {
// Pattern and related callback function
std::vector <std::pair <std::regex, void (*)(std::string&)>> patterns{};
// Initialize vector
patterns.push_back({ std::regex(".*abc.*"),function1 });
patterns.push_back({ std::regex(".*def.*"),function2 });
// Get input from user
std::string input{};
std::getline(std::cin, input);
// Find a pattern and call the corresponding function
for (size_t i{}; i < patterns.size(); i) {
if (std::regex_match(input, patterns[i].first))
patterns[i].second(input);
}
}
Modern C has more nice features, like structured bindings and range based for loops.
With that, the code can be made even more readable.
#include <iostream>
#include <string>
#include <vector>
#include <utility>
#include <regex>
void function1(std::string& s) {
std::cout << "Function 1:\t " << s << '\n';
}
void function2(std::string& s) {
std::cout << "Function 2:\t " << s << '\n';
}
int main() {
// Pattern and related callback function
std::vector <std::pair <std::regex, void (*)(std::string&)>> patterns{
{ std::regex(".*abc.*"),function1 },
{ std::regex(".*def.*"),function2 }
};
// Get input from user
std::string input{};
std::getline(std::cin, input);
// Find a pattern and call the corresponding function
for (const auto& [regex, function] : patterns) {
if (std::regex_match(input, regex))
function(input);
}
}