捕获 std::apply 中折叠表达式的返回值。

huangapple go评论72阅读模式
英文:

Capture return value from fold expression in std::apply

问题

以下是您提供的代码的翻译部分:

我有一个简单的片段,试图说明我要做的事情。
我将几个类实例打包到一个元组中,并使用std::apply迭代它们。
我想捕获两个值:

  1. 如果找到匹配的键
  2. 如果找到键,返回do_test调用的结果

我将(2)捕获到变量fn_ret中,但对于(1),我无法确定在迭代元组时是否找到了键。我认为在传递它到折叠表达式之前,我可能需要以某种方式存储/获取search_tuple(args)的结果。我该如何操作?

#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;
}

请注意,我已经进行了必要的代码格式化,以使其更具可读性。

英文:

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:

  1. If a matching key was found
  2. If a key was found, return the result of the do_test call

I 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 &lt;iostream&gt;
#include &lt;tuple&gt;

using namespace std;

class foo
{
    public:
    foo(int i) : key_(i){}
    
    int get_key()
    {
        return key_;
    }

    int do_test()
    {
        std::cout &lt;&lt; &quot;ran test for key=&quot; &lt;&lt; key_ &lt;&lt; &quot;\n&quot;;
        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, &amp;fn_ret](auto&amp;... args)
			{
				auto search_tuple = [key, &amp;fn_ret](auto&amp; x) {
				    int foo_key = x.get_key();
				    cout &lt;&lt; &quot;current key=&quot; &lt;&lt; foo_key &lt;&lt; &quot;\n&quot;;
					if (foo_key == key)
					{
						std::cout &lt;&lt; &quot;found matching key, running test!\n&quot;;
						fn_ret = x.do_test();
						return 0;
					}
					return -1;
				};
				(search_tuple(args) &amp;&amp; ...);
			}, tup
		);
    return 0;
}

答案1

得分: 2

以下是翻译好的部分:

以下的代码在相当程度上可以工作。 它在 `fn_ret` 中存储了一个特殊的初始值来检查是否找到了键。而不是从主函数一起传递一个额外的布尔变量通过引用传递 `key`  `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_; // 对键执行一些操作
    }

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;
}

根据康桓瑋的评论,可以将逻辑简化如下。请注意,折叠表达式应基于 ||,以确保键与任何一个键匹配。此外,在找到匹配后,折叠表达式的评估将停止。

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
            );
英文:

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 &lt;iostream&gt;
#include &lt;tuple&gt;
using namespace std;
class foo
{
public:
foo(int i) : key_(i){}
int get_key()
{
return key_;
}
int do_test()
{
std::cout &lt;&lt; &quot;ran test for key=&quot; &lt;&lt; key_ &lt;&lt; &quot;\n&quot;;
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, &amp;fn_ret, &amp;key_fnd](auto&amp;... args) {
auto search_tuple = [key, &amp;fn_ret, &amp;key_fnd](auto&amp; x) {
int foo_key = x.get_key();
cout &lt;&lt; &quot;current key=&quot; &lt;&lt; foo_key &lt;&lt; &quot;\n&quot;;
if (foo_key == key)
{
std::cout &lt;&lt; &quot;found matching key, running test!\n&quot;;
key_fnd = true;
fn_ret = x.do_test();
return 0;
}
return -1;
};
(search_tuple(args) &amp;&amp; ...);
}, tup
);
if (!key_fnd) {
std::cout&lt;&lt;&quot;The key was not found&quot;&lt;&lt;std::endl;
}
else {
std::cout&lt;&lt;&quot;The result of running the test on key &quot;&lt;&lt;key;
std::cout&lt;&lt;&quot; is &quot;&lt;&lt;fn_ret&lt;&lt;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, &amp;fn_ret](auto&amp;... args) {
auto search_tuple = [key, &amp;fn_ret](auto&amp; x) {
int foo_key = x.get_key();
cout &lt;&lt; &quot;current key=&quot; &lt;&lt; foo_key &lt;&lt; &quot;\n&quot;;
if (foo_key == key) {
std::cout &lt;&lt; &quot;found matching key, running test!\n&quot;;
fn_ret = x.do_test();
return true;
}
return false;
};
return (search_tuple(args) || ...);
}, tup
);

huangapple
  • 本文由 发表于 2023年5月17日 12:14:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/76268518.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定