即使有C++11/14,给出的答案仍然是"Why switch statement cannot be applied on strings?"真的吗?

Is the answer given for "Why switch statement cannot be applied on strings?" still true, even with C++11/14?

本文关键字:Why statement switch cannot applied 真的吗 strings on be 仍然是 C++11      更新时间:2023-10-16

我遇到了这个问题:为什么 switch 语句不能应用于字符串?并想知道答案是否:

原因与类型系统有关。C/C++ 并不真正支持字符串作为一种类型。它确实支持常量 char 数组的概念,但它并没有真正完全理解字符串的概念。

即使在 C++11/14 以内std:string仍然适用。有没有其他方法可以拥有几个else if(...)

是的,它仍然成立。
如此处所述,条件可以是:

整型或枚举类型的任何表达式

,或在上下文中隐式转换为整型或枚举类型的类类型的任何表达式,或具有大括号或等于初始值设定项的此类类型的单个非数组变量的声明。

几天前我遇到了这个问题,我想你可以从那里找到if/else链的替代解决方案。
如果可能的话,这主要取决于您的实际问题,无论如何,基本思想是使用可调用对象的映射,使用您的对象(在本例中为字符串(作为键进行访问。当然,这张地图在使用之前必须以某种方式填充。

如果(...s?

您可以编写自己的开关函数,而不是 switch 语句。

也许它看起来像这样:

#include <iostream>
#include <string>
#include <utility>
#include <tuple>
//pass in a bool as to whether or not we break
//make macro so it looks more like a switch statement
#define BREAK true
//template details used by outside functions
namespace switch_impl{
  //represents a case statement
  template <typename T, typename U>
  struct Case_Statement{
    U value;
    T expression;
    bool breaks;
    Case_Statement(U value, T expression, bool breaks=false)
    : value(value)
    , expression(expression)
    , breaks(breaks)
    {}
  };
  //recursive template unpacking to evaluate in a fashion similar to switch statements
  template<std::size_t I = 0, typename C, typename... Tp>
  inline typename std::enable_if<I == sizeof...(Tp), void>::type
    evaluate(C comparator, bool found, std::tuple<Tp...>& t)
    { }
  template<std::size_t I = 0, typename C, typename... Tp>
  inline typename std::enable_if<I < sizeof...(Tp), void>::type
    evaluate(C comparator, bool found, std::tuple<Tp...>& t)
    {
      if (std::get<I>(t).value == comparator || found){
        std::get<I>(t).expression();
        if (!std::get<I>(t).breaks){
          evaluate<I + 1, C, Tp...>(comparator,true,t);
        }
      }else{
          evaluate<I + 1, C, Tp...>(comparator,false,t);
      }
    }
}
//base functions to compose so that it looks like a switch statement
template<typename T, typename... Statements>  
void Switch(T comparator, Statements... statements)  
{
  auto t = std::make_tuple(statements...);
  switch_impl::evaluate(comparator,false,t);
}
template<typename T, typename U>
auto Case(U value, T expression, bool breaks=false) -> switch_impl::Case_Statement<T,U>{
  return switch_impl::Case_Statement<T,U>(value,expression,breaks);
}

//example usage
int main(){
  //c style switch example:
  switch (2){
    case 1:
    std::cout << "1n";
    break;
    case 2:
    std::cout << "2n";
    case 3: 
    std::cout << "3n";
    break;
    case 4: 
    std::cout << "4n";
    break;
  }
  //c++ functional switch example:
  Switch("2",
    Case("1",[&](){
      std::cout << "1n";
    },BREAK),
    Case("2",[&](){
      std::cout << "2n";
    }),
    Case("3",[&](){
      std::cout << "3n";
    },BREAK),
    Case("4",[&](){
      std::cout << "4n";
    },BREAK)
  );
}

我省略了默认情况,但你明白了。
事实上,您可能会意识到这比常量表达式稍微强大一些。

欢迎来到模式匹配的世界,
这是一个语言功能,我认为C++绝对可以使用。

另一种方法是将字符串映射到 std::function,但如果您需要默认大小写,这是非常丑陋的 IMO。

#include <iostream>
#include <functional>
#include <string>
#include <map>
using namespace std;
static const map<string, function<void (const string&)>> handlers {
    { "AAPL", [](const auto& str) {cout << str << " Califn";}},
    { "MSFT", [](const auto& str) {cout << str << " Washn";}}
    };
static const function <void (const string&)> default_handler = [] (const auto& str) 
    {cout << str << " Narnian";};

void f(const string& str) {
    const auto it = handlers.find(str);
    if (it !=handlers.end()) {
        it->second(str);
    }
    else 
    {
        default_handler(str);
    }
}
int main() {
    f("ABC");
    f("AAPL");
    f("MSFT");;
}

c# 在内部执行此操作的方式是获取字符串的哈希代码并对其进行切换。