推导大量模板参数的最小方法

问题描述 投票:0回答:1

我经常遇到以下最小假设示例中所示的一种问题。

我有一个这样的库函数:

/**
 * `shoes` can take values {0, 1, 2}
 * `isNew` can take values {false, true}
 * `color` can take values {'r', 'g', 'b'}
 */
template <int shoes, bool isNew, char color>
int coreFun (int p1, int p2, int p3) {
  return shoes + isNew + int(color) + p1 + p2 + p3; // shoes price.
}

现在,我需要编写一个函数供客户端使用:

/**
 * Here, `shoes`, `isNew` and `color` will all be strings or string views
 * given by clients.
 * 
 * `p1`, `p2`, `p3` are variables to coreFun().
 */
int clientAPI (
    auto && shoes, auto && isNew, auto && color,
    int p1, int p2, int p3
) 
{
  int rst = 0; // result.
  if (shoes == "snicker") {
    if (isNew == "yes") {
      if (color == "red") rst = fun <0, true, 'r'> (p1, p2, p3);
      else if (color == "green") rst = fun <0, true, 'g'> (p1, p2, p3);
      else rst = fun <0, true, 'b'> (p1, p2, p3);
    }
    else { // isNew == "no"
      if (color == "red") rst = fun <0, false, 'r'> (p1, p2, p3);
      else if (color == "green") rst = fun <0, false, 'g'> (p1, p2, p3);
      else rst = fun <0, false, 'b'> (p1, p2, p3);
    }
  }
  else if (shoes == "leather") {
    if (isNew == "yes") {
      if (color == "red") rst = fun <1, true, 'r'> (p1, p2, p3);
      else if (color == "green") rst = fun <1, true, 'g'> (p1, p2, p3);
      else rst = fun <1, true, 'b'> (p1, p2, p3);
    }
    else { // isNew == "no"
      if (color == "red") rst = fun <1, false, 'r'> (p1, p2, p3);
      else if (color == "green") rst = fun <1, false, 'g'> (p1, p2, p3);
      else rst = fun <1, true, 'b'> (p1, p2, p3);
    } 
  }
  else { // shoes == "other"
    if (isNew == "yes") {
      if (color == "red") rst = fun <2, true, 'r'> (p1, p2, p3);
      else if (color == "green") rst = fun <2, true, 'g'> (p1, p2, p3);
      else rst = fun <2, true, 'b'> (p1, p2, p3);
    }
    else { // isNew == "no"
      if (color == "red") rst = fun <2, false, 'r'> (p1, p2, p3);
      else if (color == "green") rst = fun <2, false, 'g'> (p1, p2, p3);
      else rst = fun <2, true, 'b'> (p1, p2, p3);
    }
  }
  return rst;
}

clientAPI()
的签名不得更改。

我的

clientAPI()
实现有效,但是太长了。幸运的是,在这个例子中我只有 18 种组合。在现实生活中我遇到过多达 50 个这样的模板参数。疼痛。

我打算简化实现,如下所示:

int clientAPI (
    auto && shoes, auto && isNew, auto && color,
    int p1, int p2, int p3
) 
{
  using namespace std;
  auto clientInputs = tuple(move(shoes), move(isNew), move(color));
  constexpr auto mapping = tuple(
    tuple(pair("sniker", 0), pair("leather", 1), pair("other", 2)),
    tuple(pair("no", false), pair("yes", true)),
    tuple(pair("red", 'r'), pair("green", 'g'), pair("blue", 'b'))
  );
  
  
  // ===========================================================================
  // How to (i) achieve compile time deduction of the 18 instances
  // using a some kind of constexpr loop over `clientInputs` and `mapping`,
  // and then (ii) execute the correct instance of coreFun() 
  // corresponding to `clientInputs`?
  //
  // If the above is impossible, can we achieve the goal using
  // std::function and some kind of compile time lookup table ?
  // ===========================================================================
}

我的问题已在上面的评论中列出。另外,是否有一些神奇的函数/类可以将

coreFun
clientInputs
mapping
作为参数并生成鞋子的价格?

非常感谢!!

c++ templates c++20 template-meta-programming
1个回答
0
投票

您可以使用

std::variant
std::integral_constant
按类型仅进行一次转换:

std::variant<std::false_type, std::true_type>
to_variant(bool b)
{
    switch (b) {
        case false: return std::false_type{};
        case true: return std::true_type{};
    }
}

std::variant<
    std::integral_constant<char, 'r'>,
    std::integral_constant<char, 'g'>,
    std::integral_constant<char, 'b'>,
>
to_variant_color(std::string_view color)
{
    if (color == "red") {
        return std::integral_constant<char, 'r'>{};
    } else if (color == "green") {
        return std::integral_constant<char, 'g'>{};
    } else if (color == "blue") {
        return std::integral_constant<char, 'b'>{};
    }
    throw std::runtime_error("Invalid color")
}

std::variant<
    std::integral_constant<int, 1>,
    std::integral_constant<int, 2>,
    std::integral_constant<int, 3>,
>
to_variant_shoes(std::string_view shoes)
{
    if (shoes == "snicker") {
        return std::integral_constant<int, 0>{};
    } else if (shoes == "leather") {
        return std::integral_constant<int, 1>{};
    } else if (shoes == "other") {
        return std::integral_constant<int, 2>{};
    }
    throw std::runtime_error("Invalid shoes")
}

然后,让

std::visit
进行调度:

int clientAPI (
    auto && shoes_str, auto && isNew_str, auto && color_str,
    int p1, int p2, int p3
)
{
    return std::visit(
        [&](auto shoes, auto isNew, auto color){
            return fun<shoes(), isNew(), color()>(p1, p2, p3)
        },
        to_variant_shoes(shoes_str),
        to_variant(isNewStr == std::string_view("true")),
        to_variant_color(color_str)
    );
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.