【问题标题】:Default value on generic predicate as argument - continued泛型谓词的默认值作为参数 - 续
【发布时间】:2020-08-08 18:12:26
【问题描述】:

我知道已经有Default value on generic predicate as argument

但现在可能有 c++11、c++14 或 c++17 的新选项?

我怎样才能在不超载的情况下完成这项工作?

#include <vector>
#include <numeric>
#include <algorithm>
#include <iterator>
#include <iostream>

#if 0

template <typename CONTAINER, typename PRED>
void print(CONTAINER const & cont, PRED pred = [] (typename CONTAINER::value_type) { return true;})
{
    std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred);
    std::cout << std::endl;
}

#else

template <typename CONTAINER, typename PRED>
void print(CONTAINER const & cont, PRED pred)
{
    std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred);
    std::cout << std::endl;
}

template <typename CONTAINER>
void print (CONTAINER const & cont)
{
    std::copy(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "));
    std::cout << std::endl;
}

#endif

bool
even(
        const int& i)
{
    return not (i % 2);
}

int
main(
        int argc,
        char **argv)
{
    std::vector<int> myVec(20);
    std::iota(myVec.begin(), myVec.end(), 1);

    print(myVec);

    print(myVec, even);

    return 0;
}

启用#if 0 部分会导致
../main.cpp:17:6:注意:模板参数推导/替换失败:
../main.cpp:56:13: 注意:无法推断模板参数‘PRED’

【问题讨论】:

  • 我不知道如何避免过载,但你可以让单参数print调用双参数print,从而避免重复逻辑。
  • 这是一个选项。但我正在为谓词寻找一个基本/通用类型来做 w/o 模板参数。

标签: c++ predicate


【解决方案1】:

可能是这样的:

template <typename CONTAINER>
void print(CONTAINER const & cont,
           std::function<bool(typename CONTAINER::value_type)> pred =
           [] (typename CONTAINER::value_type) { return true;})
{
    std::copy_if(cont.begin(), cont.end(),
                 std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "),
                 pred);
    std::cout << std::endl;
}

Demo。效率不是特别高,但似乎确实满足您的要求。

【讨论】:

  • 谢谢! - 这就是我最初想要的。但你是对的,它总是调用更具体的 std::copy_if()
  • 效率低下不在copy_if,在std::function。类型擦除需要堆分配和虚函数调用,而在最初的基于模板的公式中,谓词很可能会被内联。
【解决方案2】:

这对你现在可能不是特别有帮助,但你可以让它在 C++20 中工作。标准周围的 lambda 有几个变化。特别是,lambda 可以出现在未计算的操作数和模板参数中,并且无捕获 lambda 是默认可构造的。所以使用它我们可以简单地写

template <typename CONTAINER, typename PRED = decltype([] (typename CONTAINER::value_type) { return true;})>
void print(CONTAINER const & cont, PRED pred = {})
{
    std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred);
    std::cout << std::endl;
}

【讨论】:

    【解决方案3】:

    Igor 提出了一个 - 更接近我最初的意图(谢谢!)
    这是另一个:

    #include <vector>
    #include <numeric>
    #include <algorithm>
    #include <iterator>
    #include <iostream>
    
    template <typename CONTAINER, typename...OPT_PRED>
    void print(
            CONTAINER const & cont,
            OPT_PRED... optPred)
    {
        if constexpr(sizeof...(OPT_PRED) == 1)
        {
            std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), std::forward<OPT_PRED>(optPred)...);
        }
        else if constexpr(sizeof...(OPT_PRED) == 0)
        {
            std::copy(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "));
        }
        else
        {
            static_assert(sizeof...(OPT_PRED) < 0 or sizeof...(OPT_PRED) > 1, "invalid number of arguments for print()");
        }
    
        std::cout << std::endl;
    }
    
    bool
    even(
            const int& i)
    {
        return not (i % 2);
    }
    
    int
    main(
            int argc,
            char **argv)
    {
        std::vector<int> myVec(20);
        std::iota(myVec.begin(), myVec.end(), 1);
    
        print(myVec);
    
        print(myVec, even);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-06-15
      • 2016-11-14
      • 1970-01-01
      • 2018-09-12
      • 1970-01-01
      • 2022-07-24
      • 2020-06-24
      • 2021-09-11
      • 1970-01-01
      相关资源
      最近更新 更多