【问题标题】:In C++ how can I extract members from an array and return an array of the member's type? [closed]在 C++ 中,如何从数组中提取成员并返回成员类型的数组? [关闭]
【发布时间】:2018-08-24 19:59:20
【问题描述】:
namespace detail
{
    template <typename T, typename U>
    Array<U> extract_(const Array<T>& array, std::function<U(const T&)> member)
    {
        Array<U> extracted;

        for (auto& item : array)
            extracted += member(item);

        return extracted;
    }
}


#define extract(container, member) detail::extract_(container, \
    std::function< typeof(typeof(container)::Type::element_type::member) (const typeof(container)::Type&)>( \
                   [&](const typeof(container)::Type& item){ return item->member; }))

这就是我想用来从数组中提取成员的算法。 Array&lt;T&gt; 是我自己开发的数组类型,它处理出价。

如果你对宏过敏,很抱歉,但它使用户代码非常干净。

我想要做的是,如果我有Array&lt;Size&gt; sizeArray 和成员double Array&lt;Size&gt;::Length,能够说auto lengths = extract(sizeArray, Length); 并且lengthsArray&lt;double&gt; 类型。

我已经做了类似的事情

namespace detail
{
    template <typename T>
    Array<T> filter_(const Array<T>& array, std::function<bool(const T&)> condition)
    {
        Array<T> filtered;

        for (auto& item : array)
            if (condition(item)) filtered += item;

        return filtered;
    }
}


// this macro creates a capturing lambda, the item to check is called 'item'
#define filter(container, condition) detail::filter_(container, \
    std::function<bool(const typeof(container)::Type&)>( \
                   [&](const typeof(container)::Type& item){ return condition; }))

我可以使用auto turnedOff = filter(objects, !item-&gt;IsTurnedOn);,它运行良好,但它返回相同的类型,因此更容易解决。

【问题讨论】:

  • 什么是“出价”?并且“如果你对宏过敏,对不起,但它使用户代码非常干净” - 不。
  • @NeilButterworth:也许它的意思是说“生意”?如,“我可以处理我的出价”。
  • 那么问题是什么?另外,我建议decltype 而不是typeof
  • 既然您至少可以访问 C++11,为什么不使用 decltype
  • 看起来您正在尝试制作 std::copy_if 的“范围”版本

标签: c++ arrays templates preprocessor


【解决方案1】:

不要使用那些宏。请。看在上帝的份上。

现在我们已经解决了这个问题,这是一个可行的解决方案,它不涉及 std::function 的开销。

#include <iostream>
#include <vector>
#include <algorithm>

struct A
{
    int x;
    double y;
};

template <typename T, typename U>
auto extract(const std::vector<T>& vec, U T::* member)
{
    std::vector<U> result;
    result.reserve(vec.size());
    std::transform(
        std::begin(vec), std::end(vec), std::back_inserter(result),
        [member] (const T& val) { return val.*member; }
    );
    return result;
}

int main() {
    std::vector<A> as{{10, 3.14}, {42, 1.618}};
    auto result = extract(as, &A::x);
    for (auto x : result)
        std::cout << x << std::endl;
    return 0;
}

https://ideone.com/ewieLc

【讨论】:

  • 反对这些无辜的宏是怎么回事?我的意思是我知道当模块出现时我会为此付出代价,因为我的一半东西会停止工作(我希望注入会帮助解决这个问题),但这对你们来说几乎是虔诚的......我是一个单独的开发者,没有其他人在看我的代码,我喜欢我所说的“糖果代码”,即不仅结构简单,而且视觉上简单的代码。 all::the_std_decoration:: 根本不利于可读性。由于这些宏,我的 C++ 看起来像 javascript。为什么不呢?
  • 有问题的电话是 extract(as, &amp;A::x) vs detail::extract_(container, std::function&lt; typeof(typeof(container)::Type::element_type::member) (const typeof(container)::Type&amp;)&gt;([&amp;](const typeof(container)::Type&amp; item){ return item-&gt;member; })) 。它只是暗示以某种方式滥用该语言。在某些情况下您无法摆脱宏,但这不是其中之一
  • 另外,您的解决方案意味着我必须在成员名称前添加&amp;A::,这正是我在这里想要避免的。我试图将它封装在一个宏中是有原因的,以自动化这个细微的差别。 auto extractedArray = extract(otherArray, MemberName);
  • 好的,把我的解决方案包装起来:#define EXTRACT(container, member) extract(container, &amp;decltype(container)::value_type::member)。但是现在要注意如果container 是一些复杂的表达式,你的宏会爆炸。您可以继续修复这些缺陷,但它仍然是一个创可贴。
  • 这很公平。非常感谢!
猜你喜欢
  • 2020-03-10
  • 1970-01-01
  • 1970-01-01
  • 2014-12-13
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 2016-08-18
相关资源
最近更新 更多