即使使用 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 switch statement cannot be applied on strings?
想知道答案是否:
The reason why has to do with the type system. C/C++ doesn't really support strings as a type. It does support the idea of a constant char array but it doesn't really fully understand the notion of a string.
仍然适用,即使在 C++11/14 中使用 std:string
。有几个 else if(...)
的替代方案吗?
是的,它仍然成立。
如here所述,条件可以是:
any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type, or a declaration of a single non-array variable of such type with a brace-or-equals initializer.
几天前我遇到了 that question,我想你可以从那里找到 if/else
链的替代解决方案。
如果可能的话,这主要取决于您的实际问题,无论如何,基本思想是使用可调用对象的映射,从中使用您的对象(在本例中为字符串)作为键进行访问。当然,在使用之前必须以某种方式填充该地图。
Is there an alternative to having severals else if(...)'s?
您可以编写自己的 switch 函数来代替 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。
替代方法是将字符串映射到 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 << " 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");;
}
c# 在内部执行此操作的方式是获取字符串的哈希码并对其进行切换。
我遇到了这个问题: Why switch statement cannot be applied on strings? 想知道答案是否:
The reason why has to do with the type system. C/C++ doesn't really support strings as a type. It does support the idea of a constant char array but it doesn't really fully understand the notion of a string.
仍然适用,即使在 C++11/14 中使用 std:string
。有几个 else if(...)
的替代方案吗?
是的,它仍然成立。
如here所述,条件可以是:
any expression of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type, or a declaration of a single non-array variable of such type with a brace-or-equals initializer.
几天前我遇到了 that question,我想你可以从那里找到 if/else
链的替代解决方案。
如果可能的话,这主要取决于您的实际问题,无论如何,基本思想是使用可调用对象的映射,从中使用您的对象(在本例中为字符串)作为键进行访问。当然,在使用之前必须以某种方式填充该地图。
Is there an alternative to having severals else if(...)'s?
您可以编写自己的 switch 函数来代替 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。
替代方法是将字符串映射到 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 << " 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");;
}
c# 在内部执行此操作的方式是获取字符串的哈希码并对其进行切换。