【问题标题】:c++11 : easiest way to create a function always returning true to use for a function argumentc++11:创建函数的最简单方法总是返回 true 以用于函数参数
【发布时间】:2017-03-30 14:59:31
【问题描述】:

我想使用下面的模板成员函数

template <typename Entity>
class SomeCollection
{
    // ....

    template <typename Measure, typename Filter>
    Entity maximalEntity(Measure&& measure, Filter&& requirement)
    {
        auto maxEntity = Entity();
        auto maxValue = -std::numeric_limits<double>::infinity();

        for (auto ent /* some iteration method*/)
        {
            auto measurement = measure(ent);
            if (requirement(ent) && measurement > maxValue)
                std::tie(maxEntity, maxValue) = std::make_tuple { ent, measurement };
        }
        return maxEntity;
    }

    // ...
};

在没有过滤器要求的情况下从客户端代码调用此函数的最佳方法是什么(仅具有最大元素)?

我能想到的最好的是:

class Something;
double measure(Something&);
SomeCollection<Something> collection;

auto maximum = collection.maximalEntity(measure, [](const Something&) { return true; });

但我想这个 lambda 函数可以改进吗?

【问题讨论】:

    标签: function c++11 lambda


    【解决方案1】:

    不确定 lambda 可以如何改进,但您可以定义一个通用 lambda,给定任何输入都将返回始终为 true(也可以在此处使用):

    auto always_true = [](auto&&...) { return true; };
    

    你会使用它:

    auto maximum = collection.maximalEntity(measure, always_true);
    

    Live demo


    C++11 的等效实现如下:

    struct always_true {
        template<typename... Args>
        bool operator()(Args&&...) const noexcept {
            return true;
        }
    };
    

    然后将用作:

    auto maximum = collection.maximalEntity(measure, always_true{});
    

    Live demo

    【讨论】:

    • 很好的答案。只是挑剔(或者可能是风格问题):在 C++11 版本中,您可以创建 struct always_true_t 然后 const always_true_t always_true
    【解决方案2】:

    您可以创建一个返回 true 的 lambda 并将其设置为默认参数。

    auto true_filter = [](const Something& arg){ return true; };
    //auto true_filter = [](auto&& arg){ return true; }; if you have c++14
    ...
    
    template <typename Measure, typename Filter = decltype(true_filter)>
    Entity maximalEntity(Measure&& measure, Filter requirement = true_filter)
    {
    
    ...
    auto maximum = collection.maximalEntity(measure);
    

    请注意,Filter 已从 Filter&amp;&amp; 更改。我还没有让它在这里与右值引用一起工作。

    虽然明确说明可能是更好的设计。只是一个选择让它“更短”

    【讨论】:

    • 在 C++14 中添加了多态 lambda,问题标记为 C++11。您无法使用右值引用的原因是您将 always_true 定义为左值。如果您将默认模板参数设为左值引用,则 Filter&amp;&amp; 将起作用,即 decltype(true_filter)&amp;
    【解决方案3】:

    C++14:

    template<class T>
    auto always() {
      return [](auto&&...)->T{return {};};
    };
    

    或在 C++11 中:

    template<class T>
    struct always {
      template<class...Args>
      T operator()(Args&&...)const{ return {}; }
    };
    

    使用:

    collection.maximalEntity(measure, always<std::true_type>());
    

    这样做的好处是,所涉及的 lambda 的真值被编码在类型系统中,这使得编译器更容易优化其行为。

    这也可以让您执行always&lt;std::false_type&gt; 或always&lt;std::integral_constant&lt;int, 42&gt;&gt;() 等操作。

    在 C++17 中我会这样做:

    template<auto x>
    auto always() {
      return [](auto&&)->std::integral_constant<decltype(x), x>
      { return {}; };
    }
    

    这允许always&lt;true&gt;() 和always&lt;42&gt;()(可能还有always&lt;nullptr&gt;()?)。

    【讨论】:

      猜你喜欢
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 2015-12-02
      • 1970-01-01
      • 2019-05-09
      • 1970-01-01
      相关资源
      最近更新 更多