2

我正在将一些代码从 using 转换CreateProcess为使用。我需要CreateProcessboost::process::child. 问题是他们有不兼容的方式让我说“我想使用默认值”。以前的单行命令变成了十六条if语句。

我目前使用的功能是这样的(简化的):

void CreateProcess(int, float);

每个参数都有一个值,您可以使用它来指示您想要默认值。我将在这个例子中使用 0:

int int_param = ...;
float float_param = ...;

CreateProcess(0, 0); //Use both defaults
CreateProcess(int_param, 0); //Use default float
CreateProcess(0, float_param); //Use default int
CreateProcess(int_param, float_param); //No defaults

这是一种常见的设计。你知道我在说什么。我是否想使用默认值可以通过一个简单的条件来决定,例如(... ? 0 : int_param). 这允许每次CreateProcess调用都是一行代码。

CreateProcess( (... ? 0 : int_param), (... ? 0 : float_param) );

在我以前调用的地方CreateProcess,我现在想创建一个child类。像这样工作的构造函数child

template<typename ...Args>
explicit child(Args&&...args);

而不是传递一个特定的值来使用默认值,我必须传递 nothing

int int_param = ...;
float float_param = ...;

child c; //Use both defaults
child c(int_param); //Use default float
child c(float_param); //Use default int
child c(int_param, float_param); //No defaults
child c(float_param, int_param); //Argument order is irrelevant

到目前为止,我唯一的“解决方案”是使用if分支。

if (...) {
    if (...)
        child c;
    else
        child c(float_param);
} else {
    if (...)
        child c(int_param);
    else
        child c(int_param, float_param);
}

这个例子只有两个可能的参数,它变成了四个分支。实数child有四个可能的参数,所以每个实例都有十六个分支。

我想要的是某种方式来构建调用以避免这种分支。特定于的解决方案boost::process也很好。

仅供参考,最后两个参数child可能是也可能不是同一类型。

4

2 回答 2

2

如果您希望能够在调用中省略参数,并执行以下操作:

create_child();
create_child(std::make_optional(int_param));
create_child(std::make_optional(float_param),
             (... ? std::optional<int>{} : int_param);

您可以使用一些模板和递归函数。以下代码是一个示例。有一些方法可以让这变得更好,比如只创建一个child而不返回一堆,或者使用完美转发。

//Recursion base case
//Recieves values to pass to child in a tuple
//Returns created child
template <typename... Ts>
child create_child_detail(std::tuple<Ts...> t)
{
    //Is there a better way to apply a tuple to a ctor?
    return std::apply([](Ts... ts){ return child(ts...); }, t);
}

//Recursive function
//Removes arguments from variadic template and adds arguments to tuple
template <typename... Ts, typename O, typename... Os>
child create_child_detail(std::tuple<Ts...> t, std::optional<O> o, std::optional<Os>... os)
{
    if (o) //Valid optional, add value to tuple to send to child
        return create_child_detail(std::tuple_cat(t, std::make_tuple(*o)), os...);
    else //Invalid optional, value should not be added to child
        return create_child_detail(t, os...);
}

//Called by user
//Just calls create_child_detail
template <typename... Ts>
child create_child(std::optional<Ts>... ts)
{
    return create_child_detail(std::tuple<>{}, ts...);
}

空选项被删除。参数按您编写它们的顺序传递child。它可以接受任意数量的参数。我在这里在 Coliru 上对其进行了测试,因此您可以使用它。

于 2019-05-29T13:49:49.117 回答
1

使用函数创建child包含分支的对象。std::optional作为参数传递:

child make_child(const std::optional<int>& int_param,
                 const std::optional<float>& float_param)
{
    if (int_param && float_param) {
        return child(std::to_string(int_param.value()),
                     std::to_string(float_param.value()));
    }

    // Rest of the branches ...
}

这允许您创建这样的child对象:

child c = make_child(... ? std::optional<int>() : int_param,
                     ... ? std::optional<float>() : float_param);
于 2019-05-29T12:45:09.710 回答