c++之option模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ssss1223ss/article/details/79247552

引言

我们经常在golang代码中看到这样一种惯用法:根据选项option或者配置config创建一个对象,而创建对象的工厂函数CreateXXX的输入参数不是一个大的选项结构体Options,而是Option的变长参数。举个例子:

func main() {
    p := CreatePersion(WithID(123), WithName("tom"))
    log.Println(p)
}

func WithID(id int) Option {
    return func(opts *Options) {
        opts.ID = id
    }
}

func WithName(name string) Option {
    return func(opts *Options) {
        opts.Name = name
    }
}

type Option func(*Options)

type Options struct {
    ID   int
    Name string
}

func CreatePersion(opts ...Option) *Person {
    var options Options
    for _, opt := range opts {
        opt(&options)
    }

    return &Person{
        ID:   options.ID,
        Name: options.Name,
    }
}

type Person struct {
    ID   int
    Name string
}

func (p *Person) String() string {
    return fmt.Sprintf("%d %s", p.ID, p.Name)
}

Option是个函数类型,可以非常方便拓展定制自己的Option函数WithXXX,而不仅仅只是简单对Options成员赋值。
这种惯用法我们暂且称之为option模式。C++里面应该怎么实现options模式呢?

实现原理

golang版本options模式主要在2点:1. Option定义是个函数,支持闭包。2. CreateXXX函数参数支持变长参数。
这2点在c++11中均有支持,使用std::function、lambda表达式、变长模板参数即可完美解决。

实现代码

#include <functional>
#include <string>
#include <iostream>

struct Options {
    int id;
    std::string name;
};

struct Person {
    int id;
    std::string name;
};

std::ostream& operator<< (std::ostream& out, const Person& p) {
    return out << p.id << '\t' << p.name;
}

template<typename ... Opt>
Person CreatePerson(Opt&& ... opts) {
    Options options;

    // fold expression since c++17
    (std::forward<Opt>(opts)(options), ...);

    return { options.id, options.name };
}


using Option = std::function<void(Options&)>;

Option WithID(int id) {
    return [id](Options& options) {
        options.id = id;
    };
}

Option WithName(const std::string& name) {
    return [name](Options& options) {
        options.name = name;
    };
}

int main() {
    auto p = CreatePerson(WithID(123), WithName("tom"));

    std::clog << p << std::endl;
}

猜你喜欢

转载自blog.csdn.net/ssss1223ss/article/details/79247552