【问题标题】:Is there any function object to create objects in STL?是否有任何函数对象可以在 STL 中创建对象?
【发布时间】:2010-11-10 06:40:11
【问题描述】:

考虑以下类:

class Person {
public:
    // I don't want any "char *" to be converted to Person implicitly!
    explicit Person( const char * name ) : name_(name) {};

private:
    std::string name_;
};

还可以考虑以下 char* 数据数组:

char STUDENT_NAMES[][20] = {
    "Bart",
    "Liza",
    "Maggie"
};

现在,我想根据这个数组创建人的 std::list。 我所能发明的就是使用手写的 std::transform 算法 函数对象:

struct CreatePerson : public std::unary_function<const char*,Person> {
    Person operator() (const char * name) const {
        return Person(name);
    };
};

// ...

std::list<Person> students;
std::transform(
    &STUDENT_NAMES[ 0 ],
    &(STUDENT_NAMES[ sizeof(STUDENT_NAMES)/sizeof(STUDENT_NAMES[0]) ]),
    front_inserter(students),
    CreatePerson() );
// ...

是否有任何更短和/或更清晰的方法来做到这一点?也许有些标准 函数对象还是适配器?

【问题讨论】:

    标签: c++ stl functional-programming


    【解决方案1】:

    您可以通过以下方式使用boost::lambda

    #include <boost/lambda/lambda.hpp>
    #include <boost/lambda/construct.hpp>
    #include <string>
    #include <iterator>
    #include <algorithm>
    #include <list>
    
    struct person {
      explicit person(char const *name)
       :name(name) { }
    private:
      std::string name;
    };
    
    int main() {
      char names[][20] = {
        "Michael", "litb"
      };
    
      std::list<person> v;
      std::transform(names, names + 2, std::front_inserter(v), 
        boost::lambda::constructor<person>());
    }
    

    我认为标准 C++ 库没有这种方法。

    【讨论】:

    • 我希望这个数组计算是现在,最后。忽略我的愚蠢提到我在回答中临时提到什么会产生什么类型。 Srsly,早上的数组 hax 伤害了我的大脑 :) 但是,我仍然建议您将 STUDENT_NAMES 设置为 char const *names[] = { "Bart", "Lisa", ... }; - 这样它就不会再超出 20 个字符的限制了。但是,我不知道您的代码库。你这样做有充分的理由吗?
    • 您的解决方案看起来不错,谢谢!关于数组大小。感谢您的建议,但这不是问题的关键。为了便于理解,我的示例被断章取义并重写。 :)
    • @litb: const char names[][20] 不会导致数据重定位,因此允许数据存在于只读存储器中,例如 EPROM .哦,即使是 const char * names[] 也需要重定位(它是一个指针数组,这些指针需要重定位):people.redhat.com/drepper/dsohowto.pdf
    • #include std::transform( boost::begin(names), boost::end(names), ... :)
    【解决方案2】:

    你的类的构造函数是一个转换函数。您无需转换:您只需插入即可。看看this code here

    std::list<Person> ps( NAMES, NAMES+sizeof(NAMES)/sizeof(NAMES[0]) );
    

    否则,更短的解决方法是使用静态工厂函数:

    struct Person {
        static Person create( const char* name );
         ....
     };
    
     std::transform( NAMES, NAMES+sizeof(NAMES)/sizeof(NAMES[0], front_inserter( ps ),
       &Person::create );
    

    【讨论】:

    • 不,不是。请注意,我的构造函数是显式的。使用静态 create() 的第二个示例确实可以正常工作,但它只是采用我的好看。您刚刚将功能从仿函数移动到静态方法。不管怎样,谢谢你。我想看到的是一种直接创建我的对象的方法。目前在我看来,STL 中没有这样的能力。
    • 你完全正确。你要求一个更好的方法——尽管只是一点点:你不需要额外的仿函数。
    【解决方案3】:

    帮助不大,但没有标准的 ELEMENTS 宏

       sizeof(STUDENT_NAMES)/sizeof(STUDENT_NAMES[0])
    

    快速搜索没找到,但感觉我用过的每个实现都有。

    我唯一的其他建议是将 CreatePerson 变成一个模板——这样,如果你再次需要它,你只需要做 CreateObj 或类似的东西。

    【讨论】:

      【解决方案4】:

      好吧,我只写一个方法/函数,例如:

      convert(const char*[] names, std::list<Person>&);
      

      如果只是做一个简单的转换,为什么不呢?也许我没抓住重点?

      m2c

      【讨论】:

      • 重点在于重用标准库中定义的迭代代码。 “算法”标头包含大量有用的函数,可用于非常常见的迭代任务,不仅限于列表、向量、数组,还可以使用“迭代器”。
      • @xtofl:是的,我同意你的看法。我的观点是,这种情况下的附加值并不明显,因为在给定的示例中,您必须在 Person 类范围之外编写一个一元函数,而这只是为了应用标准转换算法。您的解决方案(使用构造函数)很棒,并且使用 transform 看起来很干净。但是写一个一元只是为了使用变换......
      猜你喜欢
      • 2015-07-15
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 2011-01-15
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      相关资源
      最近更新 更多