Home > Mobile >  defining constexpr variable by checking string condition
defining constexpr variable by checking string condition

Time:10-22

int run(std::string type, std::string interval)
{
  if(type == "ST"){
    if(interval == "SEC"){
      constexpr unsigned int N = 10;
      Runner<N> data();
      data.parse();
    } else{
      constexpr unsigned int N = 20;
      Runner<N> data();
      data.parse();
    }
  }
  else if(type == "JST"){
    constexpr unsigned int N = 23;
    Runner<N> data();
    data.parse();
  }
  else{
    constexpr unsigned int N = 5;
    Runner<N> data();
    data.parse();
  }
}

I want to reduce the if statements and do the conditional checks on a separate function:

constexpr unsigned int arraysize(std::string type, std::string interval){
  if(type == "ST"){
    if(interval == "SEC"){
      return 10;
    } else{
      return 20;
    }
  }
  else if(type == "JST"){
    return 23;
  }
  else{
    return 5;
  }
}

However this doesn't work because a constexpr function cannot have a parameter of nonliteral type std::string.

Is there a better way to take out conditional checks so that I end up with something like this:

int run(std::string type, std::string interval)
{
  constexpr unsigned int N = arraysize(type, interval);
  Runner<N> data();
  data.parse();
}

CodePudding user response:

run as you are showing can't work, even in principle, because you want N to be runtime-dependent. N can't be constexpr.

Alternative approach:

template<auto V>
inline constexpr auto constant = std::integral_constant<decltype(V), V>{};

template<typename F>
void apply_with_arraysize(F&& f, std::string type, std::string interval){
  if(type == "ST"){
    if(interval == "SEC"){
      f(constant<10>);
    } else{
      f(constant<20>);
    }
  }
  else if(type == "JST"){
    f(constant<23>);
  }
  else{
    f(constant<5>);
  }
}

int run(std::string type, std::string interval)
{
    apply_with_arraysize([](auto N){
        Runner<N()> data; // N instead of N() also ok, if `Runner` doesn't use `auto` non-type template argument
        data.parse();
    }, type, interval);
}

CodePudding user response:

Another alternative, with more overhead, is the std::variant approach:

std::variant<
    std::integral_constant<unsigned, 10>,
    std::integral_constant<unsigned, 20>,
    std::integral_constant<unsigned, 23>,
    std::integral_constant<unsigned, 5>,
>
arraysize(std::string type, std::string interval){
  if (type == "ST") {
    if (interval == "SEC") {
      return std::integral_constant<unsigned, 10>();
    } else {
      return std::integral_constant<unsigned, 20>();
    }
  } else if (type == "JST") {
    return std::integral_constant<unsigned, 23>();
  } else {
    return std::integral_constant<unsigned, 5>();
  }
}


int run(std::string type, std::string interval)
{
    std::visit(
        [](auto N){
            Runner<N> data{};
            data.parse();
        },
        arraysize(type, interval));
}
  • Related