【问题标题】:Make second template functional of a unary_function使 unary_function 的第二个模板函数化
【发布时间】:2021-03-30 06:40:35
【问题描述】:

我是一名 CS 学生,我有一个需要帮助的任务。任务是创建一个vectors_predicate_view 类,该类将T 类型作为第一个模板参数,将谓词作为第二个模板参数。在其构造函数中,该类应该获得 2 个std::vectors 作为参数。

这是课程:

#pragma once
#include <vector>

template<typename T, typename Predicate>
class vectors_predicate_view 
{
private:
    Predicate predict;
    std::vector<T> originalContents1;
    std::vector<T> originalContents2;

    std::vector<T> &original1; // reference to original vector1
    std::vector<T> &original2; // reference to original vector2

    void setElements(std::vector<T> &vector1, std::vector<T> &vector2)
    {
        //Putting every element from vector1 into originalContents1
        for(auto element : vector1)
            originalContents1.push_back(element);
        vector1.clear();    //Emptying vector1

        //Putting every element from vector2 into originalContents2
        for(auto element : vector2)
            originalContents2.push_back(element);
        vector2.clear();    //Emptying vector2

        //We loop through originalContents1
        //if the element gives back true for the predictatum, we add it to vector1
        //else it goes to vector2
        for(auto element : originalContents1) 
        {
            if (predict(element))
                vector1.push_back(element);
            else
                vector2.push_back(element);
        }

        //We loop through originalContents2
        //if the element gives back true for the predictatum, we add it to vector1
        for(auto element : originalContents2)
            if(predict(element))
                vector1.push_back(element);
    }

public:
    vectors_predicate_view(std::vector<T> &vector1, std::vector<T> &vector2) : original1(vector1), original2(vector2)
    {
        setElements(vector1, vector2);
    }
};

任务是使第二个参数成为可选参数,如果没有给出,该类不应对其构造函数中的 2 个给定向量做任何事情。

只是给出一个想法,这是第二个模板的最佳外观。这是一个std::unary_function,看起来像这样:

struct is_even: std::unary_function<int, bool>
{
    bool operator()(int i) const
    {
        return 0 == i % 2;
    }
};

struct is_good_language: std::unary_function<std::string, bool>
{
    bool operator()(const std::string& s) const
    {
        return s == "C++" || s == "C";
    }
};

并像这样调用:

const vectors_predicate_view<int, is_even> va(a, b);
vectors_predicate_view<std::string, is_good_language> vb(x, y);

任何帮助将不胜感激!

【问题讨论】:

  • 你应该修改传递给构造函数的向量,还是在视图中创建新的向量?此外,您需要的可能只是一个始终返回 true 的谓词。
  • @L.F.两个都。我必须更改传递给构造函数的向量并将它们在类中的原始状态复制到两个新向量中,因此当调用析构函数时,这两个向量可以根据我的 2 个新向量重置为其原始状态在类内部创建。如何确定我创建并始终返回 true 的谓词是否不是通过第二个模板的谓词?

标签: c++ function templates


【解决方案1】:

无论参数是什么,您都可以定义一个始终返回 true 的谓词:

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

然后,将此谓词设置为模板参数Predicate的默认参数:

template <typename T, typename Predicate = always_true>
                                      // ^^^^^^^^^^^^^ default argument
class vectors_predicate_view {
    // ...
};

当用户明确提供参数时,默认参数将被忽略。


为了将默认情况与用户提供的谓词区分开来,另一种方法是将标签放在详细命名空间中——按照惯例,这对实现来说是私有的——并使用专门化来处理这种情况:

namespace detail {
    struct tag {};
}

template <typename T, typename Predicate = detail::tag>
                                      // ^^^^^ default argument
class vectors_predicate_view {
    // normal case
};

template <typename T>
class vectors_predicate_view<T, detail::tag> {
    // default case
};

当用户没有提供第二个模板参数时,使用特化。这可能会导致一些代码重复,但它可以让您完全控制默认情况下的操作。


除此之外:由于 C++11,没有必要从 unary_function 等派生出来——参见 Why have unary_function, binary_function been removed from C++11?

【讨论】:

  • 感谢您的帮助! :D 如何确定我创建并始终返回 true 的谓词是否不是通过第二个模板传递的谓词?因为如果它是我们创建的那个,那么我们不应该在vectors_predicate_view 类中做任何事情
  • @MartinSerdült 您可以将谓词放在“detail”命名空间中(按照惯例,这是实现私有的),并在主模板之后添加一个特化:template &lt;typename T&gt; class vectors_predicate_view&lt;T, always_true&gt;
  • 好吧,我有点迷路了:'D 所以我创建了一个名为“detail”的命名空间,但是在主模板之后添加一个特化是什么意思:template &lt;typename T&gt; class vectors_predicate_view&lt;T, always_true&gt;
  • @MartinSerdült 我已经更新了我的答案,希望能够澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多