答案是"为什么switch语句不能应用于字符串?"仍然如此,即使使用C ++ 11/14?

时间:2016-02-14 00:15:53

标签: c++ string c++11 std stdstring

我遇到了这个问题: Why switch statement cannot be applied on strings? 并想知道答案:

  

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

仍然适用,即使在C ++ 11/14中使用std:string也是如此。是否可以选择多个else if(...)'

4 个答案:

答案 0 :(得分:3)

是的,它仍然有效 如上所述here,条件可以是:

  

任何整数或枚举类型的表达式,或者上下文隐式可转换为整数或枚举类型的类类型的表达式,或者使用大括号或等号初始化程序的此类型的单个非数组变量的声明。

我几天前遇到that question,我想你可以从那里找出if/else链的替代解决方案。
如果可能的话,它主要取决于你的实际问题,无论如何,基本的想法是使用可调用对象的映射,使用你的对象(在这种情况下为字符串)作为键来访问它。当然,必须以某种方式填写该地图才能使用它。

答案 1 :(得分:3)

  

除了(......)之外,还有别的选择吗?

您可以编写自己的切换功能,而不是使用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 << "1\n";
    break;

    case 2:
    std::cout << "2\n";

    case 3: 
    std::cout << "3\n";
    break;

    case 4: 
    std::cout << "4\n";
    break;
  }

  //c++ functional switch example:
  Switch("2",

    Case("1",[&](){
      std::cout << "1\n";
    },BREAK),

    Case("2",[&](){
      std::cout << "2\n";
    }),

    Case("3",[&](){
      std::cout << "3\n";
    },BREAK),

    Case("4",[&](){
      std::cout << "4\n";
    },BREAK)
  );

}

我遗漏了默认情况,但你明白了。
实际上,您可能会意识到这比常量表达式更强大。

欢迎来到模式匹配的世界,
这是一种语言功能,我认为C++ could definitely use

答案 2 :(得分:0)

替代方法是将字符串映射到std :: function,但如果你需要默认情况,它就是非常难看的IMO esp。

#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 << " Calif\n";}},
    { "MSFT", [](const auto& str) {cout << str << " Wash\n";}}
    };
static const function <void (const string&)> default_handler = [] (const auto& str) 
    {cout << str << " Narnia\n";};


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");;
}

答案 3 :(得分:0)

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