I have a simple snippet that tries to illustrate what I'm trying to do. I pack a few class instances in a tuple and iterate over them using std::apply. I'd like to capture two values:
do_test
callI capture (2) in a variable fn_ret
, but for (1), I can't tell if a key was found while iterating over the tuple. I think I might need to store/get the result of search_tuple(args)
somehow before passing it in the fold expression. How do I go about doing that?
#include <iostream>
#include <tuple>
using namespace std;
class foo
{
public:
foo(int i) : key_(i){}
int get_key()
{
return key_;
}
int do_test()
{
std::cout << "ran test for key=" << key_ << "\n";
return -1;
}
private:
int key_;
};
int main()
{
std::tuple tup { foo{1}, foo{2}, foo{3}, foo{4}, foo{5}, foo{6}, foo{7}, foo{8} };
int key = 4;
int fn_ret = 0;
std::apply
(
[key, &fn_ret](auto&... args)
{
auto search_tuple = [key, &fn_ret](auto& x) {
int foo_key = x.get_key();
cout << "current key=" << foo_key << "\n";
if (foo_key == key)
{
std::cout << "found matching key, running test!\n";
fn_ret = x.do_test();
return 0;
}
return -1;
};
(search_tuple(args) && ...);
}, tup
);
return 0;
}
The following code works to a reasonable extent. It stores a special initial value in fn_ret
to check whether the key was found. Instead an additional boolean variable could be passed by reference from main along with key
and fn_ret
.
#include <iostream>
#include <tuple>
using namespace std;
class foo
{
public:
foo(int i) : key_(i){}
int get_key()
{
return key_;
}
int do_test()
{
std::cout << "ran test for key=" << key_ << "\n";
return key_*key_; // Some operation on the key
}
private:
int key_;
};
int main()
{
std::tuple tup { foo{1}, foo{2}, foo{3}, foo{4}, foo{5}, foo{6}, foo{7}, foo{8} };
int key = 10;
int fn_ret = -1;
bool key_fnd = false;
std::apply
(
[key, &fn_ret, &key_fnd](auto&... args) {
auto search_tuple = [key, &fn_ret, &key_fnd](auto& x) {
int foo_key = x.get_key();
cout << "current key=" << foo_key << "\n";
if (foo_key == key)
{
std::cout << "found matching key, running test!\n";
key_fnd = true;
fn_ret = x.do_test();
return 0;
}
return -1;
};
(search_tuple(args) && ...);
}, tup
);
if (!key_fnd) {
std::cout<<"The key was not found"<<std::endl;
}
else {
std::cout<<"The result of running the test on key "<<key;
std::cout<<" is "<<fn_ret<<std::endl;
}
return 0;
}
As per 康桓瑋's comment, the logic can be simplified as shown below. Note, the fold expression should be based on ||
to ensure that the key matches with any one of the keys. Also, the evaluation of the fold expression stops when a match has been found.
bool key_fnd = std::apply(
[key, &fn_ret](auto&... args) {
auto search_tuple = [key, &fn_ret](auto& x) {
int foo_key = x.get_key();
cout << "current key=" << foo_key << "\n";
if (foo_key == key) {
std::cout << "found matching key, running test!\n";
fn_ret = x.do_test();
return true;
}
return false;
};
return (search_tuple(args) || ...);
}, tup
);