ทำไมคำสั่ง switch ไม่สามารถใช้กับสตริงได้


227

type illegalรวบรวมรหัสต่อไปและมีข้อผิดพลาดของ

int main()
{
    // Compilation error - switch expression of type illegal
    switch(std::string("raj"))
    {
    case"sda":
    }
}

คุณไม่สามารถใช้สตริงทั้งในหรือswitch caseทำไม? มีวิธีใดที่ทำงานได้ดีในการรองรับตรรกะที่คล้ายกับการเปิดสตริง?


6
มีทางเลือกเสริมที่ซ่อนการสร้างแผนที่หรือไม่นับหลัง MACRO?
balki

@balki ฉันไม่แน่ใจเกี่ยวกับการเพิ่ม แต่มันง่ายที่จะเขียนมาโคร ในกรณีของ Qt คุณสามารถซ่อนการแมปด้วยQMetaEnum
phuclv

คำตอบ:


189

สาเหตุที่เกี่ยวข้องกับระบบการพิมพ์ C / C ++ ไม่รองรับสตริงเป็นชนิด มันสนับสนุนแนวคิดของอาเรย์ถ่านคงที่ แต่มันไม่เข้าใจความคิดของสตริงอย่างแท้จริง

เพื่อสร้างรหัสสำหรับคำสั่ง switch คอมไพเลอร์จะต้องเข้าใจว่ามันหมายความว่าอะไรสำหรับสองค่าให้เท่ากัน สำหรับรายการที่ชอบ ints และ enums นี่เป็นการเปรียบเทียบบิตเล็กน้อย แต่คอมไพเลอร์ควรเปรียบเทียบ 2 ค่าสตริงอย่างไร คำนึงถึงขนาดตัวพิมพ์เล็กและตัวพิมพ์เล็กตระหนักถึงวัฒนธรรม ฯลฯ ... หากปราศจากการรับรู้เต็มรูปแบบของสตริงสิ่งนี้ไม่สามารถตอบได้อย่างถูกต้อง

นอกจากนี้ C / C ++ งบสวิทช์จะถูกสร้างขึ้นมักจะเป็นตารางสาขา มันไม่ง่ายเลยที่จะสร้างตารางสาขาสำหรับสวิตช์สไตล์สตริง


11
อาร์กิวเมนต์ตารางสาขาไม่ควรนำไปใช้ - นั่นเป็นเพียงแนวทางเดียวที่เป็นไปได้สำหรับผู้สร้างคอมไพเลอร์ สำหรับคอมไพเลอร์ผู้ผลิตต้องใช้หลายวิธีขึ้นอยู่กับความซับซ้อนของสวิตช์
ฐานราก

5
@ แท่นฉันใส่ส่วนใหญ่ไว้ด้วยเหตุผลทางประวัติศาสตร์ คำถาม "ทำไม C / C ++ ทำสิ่งนี้มาก" สามารถตอบได้อย่างง่ายดายโดยประวัติของคอมไพเลอร์ ในขณะที่พวกเขาเขียนมัน C ได้รับการสรรเสริญและด้วยเหตุนี้สวิตช์จึงเป็นตารางสาขาที่สะดวกสบาย
JaredPar

114
ฉันลงคะแนนเพราะฉันไม่เข้าใจว่าคอมไพเลอร์รู้วิธีการเปรียบเทียบค่าสตริง 2 รายการในกรณีที่ข้อความสั่ง แต่ลืมวิธีการทำสิ่งเดียวกันในข้อความสั่งสวิตช์

15
ฉันไม่คิดว่า 2 ย่อหน้าแรกนั้นเป็นเหตุผลที่ถูกต้อง โดยเฉพาะอย่างยิ่งตั้งแต่ C ++ 14 เมื่อstd::stringเพิ่มตัวอักษร มันเป็นประวัติศาสตร์ส่วนใหญ่ แต่ปัญหาหนึ่งที่ไม่มาใจคือมีวิธีการswitchทำงานในปัจจุบันซ้ำcases จะต้องถูกตรวจพบที่รวบรวมเวลา; อย่างไรก็ตามสิ่งนี้อาจไม่ง่ายนักสำหรับสตริง (พิจารณาการเลือกสถานที่เกิดเหตุและอื่น ๆ ) ฉันคิดว่าสิ่งนั้นจะต้องมีconstexprกรณีหรือเพิ่มในพฤติกรรมที่ไม่ระบุ (ไม่เคยเป็นสิ่งที่เราต้องการจะทำ)
MM

8
มีคำจำกัดความที่ชัดเจนของวิธีการเปรียบเทียบstd::stringค่าสองค่าหรือแม้กระทั่งstd::stringกับอาร์เรย์ const char (เช่นโดยใช้ operator ==) ไม่มีเหตุผลทางเทคนิคที่จะป้องกันไม่ให้คอมไพเลอร์สร้างคำสั่งเปลี่ยนสำหรับประเภทใด ๆ ที่ให้บริการตัวนั้น มันจะเปิดคำถามบางอย่างเกี่ยวกับสิ่งต่าง ๆ เช่นอายุการใช้งานของ lables แต่ทั้งหมดนี้เป็นการตัดสินใจออกแบบภาษาไม่ใช่ปัญหาทางเทคนิค
MikeMB

60

ดังที่ได้กล่าวไปแล้วคอมไพเลอร์ต้องการสร้างตารางการค้นหาที่ปรับswitchคำสั่งให้ใกล้เคียงกับเวลา O (1) ทุกครั้งที่ทำได้ รวมสิ่งนี้เข้ากับข้อเท็จจริงที่ว่าภาษา C ++ ไม่มีประเภทสตริง - std::stringเป็นส่วนหนึ่งของไลบรารีมาตรฐานซึ่งไม่ได้เป็นส่วนหนึ่งของภาษาต่อ

ฉันจะเสนอทางเลือกที่คุณอาจต้องการพิจารณาฉันเคยใช้มันในอดีตเพื่อผลที่ดี แทนที่จะสลับไปตามสายอักขระให้สลับไปที่ผลลัพธ์ของฟังก์ชันแฮชที่ใช้สตริงเป็นอินพุต รหัสของคุณจะเกือบจะชัดเจนเหมือนการสลับสายถ้าคุณใช้ชุดของสตริงที่กำหนดไว้ล่วงหน้า:

enum string_code {
    eFred,
    eBarney,
    eWilma,
    eBetty,
    ...
};

string_code hashit (std::string const& inString) {
    if (inString == "Fred") return eFred;
    if (inString == "Barney") return eBarney;
    ...
}

void foo() {
    switch (hashit(stringValue)) {
    case eFred:
        ...
    case eBarney:
        ...
    }
}

มีการเพิ่มประสิทธิภาพที่เห็นได้ชัดที่ติดตามสิ่งที่คอมไพเลอร์ C จะทำกับคำสั่งเปลี่ยน ... ตลกว่าเกิดอะไรขึ้น


15
มันน่าผิดหวังจริง ๆ เพราะคุณไม่ได้คร่ำครวญ ด้วย C ++ ที่ทันสมัยคุณสามารถแฮชจริงในเวลารวบรวมโดยใช้ฟังก์ชันแฮ็ก constexpr วิธีการแก้ปัญหาของคุณดูสะอาดตา แต่มีสิ่งที่น่ารังเกียจหากบันไดเกิดขึ้นอย่างน่าเสียดาย โซลูชันแผนที่ด้านล่างจะดีกว่าและหลีกเลี่ยงการเรียกใช้ฟังก์ชันเช่นกัน นอกจากนี้ด้วยการใช้สองแผนที่คุณสามารถสร้างข้อความเพื่อบันทึกข้อผิดพลาดได้เช่นกัน
Dirk Bester

นอกจากนี้คุณยังสามารถหลีกเลี่ยง Enum ด้วย lambdas: stackoverflow.com/a/42462552/895245
Ciro Santilli 郝海东冠状病病六四事件法轮功

hashit อาจเป็นฟังก์ชัน constexpr หรือไม่ ระบุว่าคุณผ่าน const char * แทนที่จะเป็นสตริง std ::
Victor Stone

แต่ทำไม คุณจะได้รับการใช้การดำเนินการคำสั่ง if ตลอดเวลาบนสวิตช์ ทั้งคู่มีผลกระทบน้อยที่สุด แต่ข้อดีด้านประสิทธิภาพการทำงานพร้อมสวิตช์จะถูกลบโดยการค้นหาแบบอื่น การใช้ if-else ควรเร็วกว่าเล็กน้อย แต่ที่สำคัญกว่านั้นคือสั้นกว่ามาก
Zoe

20

C ++

ฟังก์ชันแฮชของ constexpr:

constexpr unsigned int hash(const char *s, int off = 0) {                        
    return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off];                           
}                                                                                

switch( hash(str) ){
case hash("one") : // do something
case hash("two") : // do something
}

1
คุณต้องตรวจสอบให้แน่ใจว่าไม่มีกรณีใด ๆ ของคุณแฮชเป็นค่าเดียวกัน และถึงตอนนั้นคุณอาจมีข้อผิดพลาดบางอย่างที่สตริงอื่นที่แฮชไปเช่นค่าเดียวกับแฮช ("หนึ่ง") จะทำ "บางอย่าง" ครั้งแรกในสวิตช์ของคุณอย่างไม่ถูกต้อง
David Ljung Madison Stellar

ฉันรู้ แต่ถ้ามันมีค่าเท่ากันมันจะไม่คอมไพล์และคุณจะสังเกตได้ทันเวลา
นิค

จุดดี - แต่นั่นไม่ได้แก้ปัญหาการแฮชสำหรับสตริงอื่น ๆ ที่ไม่ได้เป็นส่วนหนึ่งของสวิตช์ของคุณ ในบางกรณีที่อาจไม่สำคัญ แต่ถ้านี่เป็นวิธีการแก้ปัญหา "go-to" ทั่วไปฉันสามารถจินตนาการได้ว่ามันเป็นปัญหาด้านความปลอดภัยหรือในบางประเด็น
David Ljung Madison Stellar

7
คุณสามารถเพิ่ม a operator ""เพื่อทำให้โค้ดสวยงามยิ่งขึ้น constexpr inline unsigned int operator "" _(char const * p, size_t) { return hash(p); }และใช้งานได้เหมือนcase "Peter"_: break; Demo
hare1039

15

การอัปเดต C ++ 11 ไม่ชัดเจนว่า @MarmouCorp ด้านบน แต่http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm

ใช้สองแม็พเพื่อแปลงระหว่างสตริงและคลาส enum (ดีกว่า enum ธรรมดาเนื่องจากค่าของมันถูกกำหนดขอบเขตไว้ภายในและย้อนกลับการค้นหาสำหรับข้อความแสดงข้อผิดพลาดที่ดี)

การใช้สแตติกในโค้ด codeguru นั้นเป็นไปได้ด้วยการสนับสนุนคอมไพเลอร์สำหรับรายการตัวเริ่มต้นซึ่งหมายถึง VS 2013 plus gcc 4.8.1 ก็โอเคกับมันไม่แน่ใจว่ามันจะเข้ากันได้ไกลแค่ไหน

/// <summary>
/// Enum for String values we want to switch on
/// </summary>
enum class TestType
{
    SetType,
    GetType
};

/// <summary>
/// Map from strings to enum values
/// </summary>
std::map<std::string, TestType> MnCTest::s_mapStringToTestType =
{
    { "setType", TestType::SetType },
    { "getType", TestType::GetType }
};

/// <summary>
/// Map from enum values to strings
/// </summary>
std::map<TestType, std::string> MnCTest::s_mapTestTypeToString
{
    {TestType::SetType, "setType"}, 
    {TestType::GetType, "getType"}, 
};

...

std::string someString = "setType";
TestType testType = s_mapStringToTestType[someString];
switch (testType)
{
    case TestType::SetType:
        break;

    case TestType::GetType:
        break;

    default:
        LogError("Unknown TestType ", s_mapTestTypeToString[testType]);
}

ฉันควรทราบว่าในภายหลังฉันพบวิธีแก้ปัญหาที่ต้องการตัวอักษรสตริงและการคำนวณเวลารวบรวม (C ++ 14 หรือ 17 ฉันคิดว่า) ที่คุณสามารถแฮชสตริงกรณีที่เวลารวบรวมและแฮชสตริงสวิทช์ที่รันไทม์ มันจะคุ้มค่าสำหรับสวิตช์ที่มีความยาวมาก ๆ แต่บางทีก็สามารถใช้งานร่วมกันได้น้อยลงถ้ามันสำคัญ
Dirk Bester

คุณช่วยแบ่งปันโซลูชันเวลาคอมไพล์ที่นี่ได้ไหม ขอบคุณ!
qed

12

ปัญหาคือว่าด้วยเหตุผลของการปรับให้เหมาะสมคำสั่ง switch ใน C ++ จะไม่ทำงานกับอะไรนอกจากชนิดดั้งเดิมและคุณสามารถเปรียบเทียบได้กับค่าคงที่เวลาที่คอมไพล์เท่านั้น

เหตุผลที่น่าจะเป็นไปได้สำหรับข้อ จำกัด คือคอมไพเลอร์สามารถใช้การเพิ่มประสิทธิภาพบางรูปแบบในการคอมไพล์โค้ดลงไปในคำสั่ง cmp หนึ่งคำสั่งและ goto ซึ่งการคำนวณที่อยู่นั้นขึ้นอยู่กับค่าของอาร์กิวเมนต์ที่รันไทม์ เนื่องจากการแยกและลูปไม่ได้เล่นกับซีพียูสมัยใหม่อย่างดีนี่อาจเป็นการเพิ่มประสิทธิภาพที่สำคัญ

เพื่อไปรอบ ๆ นี้ฉันกลัวว่าคุณจะต้องใช้ถ้างบ


เวอร์ชันที่ปรับให้เหมาะสมที่สุดของคำสั่ง switch ที่สามารถทำงานกับสตริงนั้นเป็นไปได้อย่างแน่นอน ความจริงที่ว่าพวกเขาไม่สามารถใช้เส้นทางรหัสเดียวกันกับที่ใช้สำหรับประเภทดั้งเดิมไม่ได้หมายความว่าพวกเขาไม่สามารถทำได้std::stringและคนอื่น ๆ ในภาษาแรกและสนับสนุนพวกเขาในคำสั่งเปลี่ยนด้วยอัลกอริทึมที่มีประสิทธิภาพ
ceztko

10

std::map + รูปแบบ lambdas โดยไม่มี enums

unordered_mapสำหรับค่าตัดจำหน่ายที่อาจเกิดขึ้นO(1): วิธีที่ดีที่สุดในการใช้ HashMap ใน C ++ คืออะไร

#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

int main() {
    int result;
    const std::unordered_map<std::string,std::function<void()>> m{
        {"one",   [&](){ result = 1; }},
        {"two",   [&](){ result = 2; }},
        {"three", [&](){ result = 3; }},
    };
    const auto end = m.end();
    std::vector<std::string> strings{"one", "two", "three", "foobar"};
    for (const auto& s : strings) {
        auto it = m.find(s);
        if (it != end) {
            it->second();
        } else {
            result = -1;
        }
        std::cout << s << " " << result << std::endl;
    }
}

เอาท์พุท:

one 1
two 2
three 3
foobar -1

วิธีการใช้งานภายในด้วย static

หากต้องการใช้รูปแบบนี้อย่างมีประสิทธิภาพภายในชั้นเรียนให้เริ่มต้นแผนที่แลมบ์ดาแบบคงที่หรืออื่นที่คุณจ่าย O(n)ทุกครั้งเพื่อสร้างตั้งแต่เริ่มต้น

ที่นี่เราสามารถไปด้วยการ{}เริ่มต้นของstaticตัวแปรวิธีการ: ตัวแปรคงที่ในวิธีการเรียนแต่เรายังสามารถใช้วิธีการที่อธิบายไว้ที่: constructors คงที่ใน C ++? ฉันต้องเริ่มต้นวัตถุคงที่ส่วนตัว

มันจำเป็นที่จะต้องแปลงบริบทแลมบ์ดา[&]ให้เป็นข้อโต้แย้งหรืออาจจะไม่ได้กำหนด: const แลมบ์ดาสแตติกอัตโนมัติที่ใช้กับการดักจับ

ตัวอย่างที่สร้างเอาต์พุตเดียวกันกับด้านบน:

#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>

class RangeSwitch {
public:
    void method(std::string key, int &result) {
        static const std::unordered_map<std::string,std::function<void(int&)>> m{
            {"one",   [](int& result){ result = 1; }},
            {"two",   [](int& result){ result = 2; }},
            {"three", [](int& result){ result = 3; }},
        };
        static const auto end = m.end();
        auto it = m.find(key);
        if (it != end) {
            it->second(result);
        } else {
            result = -1;
        }
    }
};

int main() {
    RangeSwitch rangeSwitch;
    int result;
    std::vector<std::string> strings{"one", "two", "three", "foobar"};
    for (const auto& s : strings) {
        rangeSwitch.method(s, result);
        std::cout << s << " " << result << std::endl;
    }
}

3
โปรดทราบว่ามีความแตกต่างระหว่างวิธีการนี้และswitchคำสั่ง การทำซ้ำค่าเคสในswitchคำสั่งคือการรวบรวมเวลาที่ล้มเหลว การใช้std::unordered_mapยอมรับค่าที่ซ้ำกันอย่างเงียบ ๆ
D.Shawley

6

ใน C ++ และ C Switch จะทำงานกับประเภทจำนวนเต็มเท่านั้น ใช้บันไดถ้าอย่างอื่นแทน เห็นได้ชัดว่า C ++ สามารถใช้คำสั่ง swich บางอย่างสำหรับสตริง - ฉันเดาว่าไม่มีใครคิดว่ามันคุ้มค่าและฉันเห็นด้วยกับพวกเขา


เห็นด้วย แต่คุณรู้ไหมว่าอะไรทำให้ไม่สามารถใช้สิ่งนี้ได้
yesraaj

ประวัติศาสตร์? การสลับจำนวนจริงพอยน์เตอร์และโครงสร้าง (ประเภทข้อมูลอื่น ๆ ของ C เท่านั้น) ไม่ได้ทำให้เป็น sanse ดังนั้น C จึง จำกัด ให้เป็นจำนวนเต็ม

โดยเฉพาะถ้าคุณเปิดคลาสที่อนุญาตให้มีการแปลงโดยนัยคุณจะมีช่วงเวลาที่ดีจริงๆ
sharptooth

6

ทำไมจะไม่ล่ะ? คุณสามารถใช้การประยุกต์ใช้สวิตช์ด้วยไวยากรณ์ที่เทียบเท่าและซีแมนทิกส์เดียวกัน Cภาษาไม่ได้มีวัตถุและวัตถุสตริงเลย แต่ในสตริงCเป็นโมฆะยกเลิกสตริงอ้างอิงโดยตัวชี้ C++ภาษามีความเป็นไปได้ที่จะทำให้การทำงานเกินพิกัดสำหรับวัตถุเปรียบเทียบหรือการตรวจสอบวัตถุ equalities ในฐานะที่Cเป็นC++ก็พอมีความยืดหยุ่นที่จะมีสวิทช์ดังกล่าวสำหรับสตริงสำหรับC ภาษาและสำหรับวัตถุชนิดใด ๆ ที่สนับสนุน comparaison หรือความเท่าเทียมกันตรวจสอบC++ภาษา และทันสมัยC++11อนุญาตให้มีการใช้สวิตช์นี้มีประสิทธิภาพเพียงพอ

รหัสของคุณจะเป็นเช่นนี้:

std::string name = "Alice";

std::string gender = "boy";
std::string role;

SWITCH(name)
  CASE("Alice")   FALL
  CASE("Carol")   gender = "girl"; FALL
  CASE("Bob")     FALL
  CASE("Dave")    role   = "participant"; BREAK
  CASE("Mallory") FALL
  CASE("Trudy")   role   = "attacker";    BREAK
  CASE("Peggy")   gender = "girl"; FALL
  CASE("Victor")  role   = "verifier";    BREAK
  DEFAULT         role   = "other";
END

// the role will be: "participant"
// the gender will be: "girl"

มันเป็นไปได้ที่จะใช้ประเภทที่ซับซ้อนมากขึ้นเช่นstd::pairsหรือ structs หรือคลาสใด ๆ ที่สนับสนุนการดำเนินงานที่เท่าเทียมกัน (หรือ comarisions เพื่อความรวดเร็วโหมด )

คุณสมบัติ

  • ข้อมูลชนิดใดก็ได้ที่สนับสนุนการเปรียบเทียบหรือตรวจสอบความเท่าเทียมกัน
  • ความเป็นไปได้ในการสร้างสถิติสวิตช์ซ้อนซ้อน
  • ความเป็นไปได้ที่จะทำลายหรือลดลงผ่านคำสั่งกรณี
  • ความเป็นไปได้ที่จะใช้นิพจน์กรณีไม่ใช่แบบคงที่
  • เป็นไปได้ที่จะเปิดใช้งานโหมดสแตติก / ไดนามิกอย่างรวดเร็วด้วยการค้นหาต้นไม้ (สำหรับ C ++ 11)

ความแตกต่าง Sintax กับสวิตช์ภาษาคือ

  • คำหลักตัวพิมพ์ใหญ่
  • ต้องการวงเล็บสำหรับคำสั่ง CASE
  • อัฒภาค ';' ไม่อนุญาตให้ใช้ที่ส่วนท้ายของข้อความ
  • โคลอน ':' ที่คำสั่ง CASE ไม่ได้รับอนุญาต
  • ต้องการหนึ่งในคำหลัก BREAK หรือ FALL ที่ท้ายคำสั่ง CASE

สำหรับC++97ภาษาที่ใช้การค้นหาเชิงเส้น เพื่อC++11ความทันสมัยและเป็นไปได้มากขึ้นที่จะใช้การquickค้นหาแบบทรี wuth tree ที่ไม่อนุญาตให้ใช้คำสั่งreturnใน CASE การCใช้ภาษาอยู่ที่ไหนchar*เมื่อมีการใช้การเปรียบเทียบสตริงประเภทและสิ้นสุดด้วยศูนย์

อ่านเพิ่มเติมเกี่ยวกับการติดตั้งสวิตช์นี้


6

หากต้องการเพิ่มรูปแบบโดยใช้คอนเทนเนอร์ที่ง่ายที่สุดเท่าที่จะเป็นไปได้ (ไม่จำเป็นต้องใช้แผนที่ที่มีการสั่งซื้อ) ... ฉันไม่รำคาญกับ enum - เพียงแค่ใส่คำจำกัดความของคอนเทนเนอร์ทันทีก่อนสวิตช์ดังนั้นมันจะง่ายต่อการดูว่า ซึ่งในกรณีนี้

นี่เป็นการค้นหาที่ถูกแฮชในunordered_mapและใช้การเชื่อมโยงintเพื่อขับเคลื่อนคำสั่ง switch ควรจะค่อนข้างเร็ว โปรดทราบว่าatจะใช้แทน[]เพราะฉันได้ทำภาชนะconstนั้น การใช้[]อาจเป็นอันตรายได้ - หากสตริงไม่ได้อยู่ในแผนที่คุณจะสร้างการแมปใหม่และอาจจบลงด้วยผลลัพธ์ที่ไม่ได้กำหนดหรือแผนที่ที่เติบโตอย่างต่อเนื่อง

โปรดทราบว่าat()ฟังก์ชั่นจะส่งข้อยกเว้นหากสตริงไม่ได้อยู่ในแผนที่ count()ดังนั้นคุณอาจต้องการที่จะทดสอบครั้งแรกที่ใช้

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
switch(string_to_case.at("raj")) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;


}

เวอร์ชันที่มีการทดสอบสตริงที่ไม่ได้กำหนดมีดังนี้:

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
// in C++20, you can replace .count with .contains
switch(string_to_case.count("raj") ? string_to_case.at("raj") : 0) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;
  case 0: //this is for the undefined case

}

4

ฉันคิดว่าเหตุผลก็คือในสตริง C ไม่ใช่ประเภทดึกดำบรรพ์อย่างที่ tomjen พูดคิดในสายอักขระเป็นอาเรย์ถ่านดังนั้นคุณจึงไม่สามารถทำสิ่งต่าง ๆ เช่น:

switch (char[]) { // ...
switch (int[]) { // ...

3
โดยไม่ต้องมองหามันอาร์เรย์ของตัวอักษรน่าจะเสื่อมสภาพไปเป็น char * ซึ่งแปลงเป็นประเภทอินทิกรัลโดยตรง ดังนั้นมันอาจรวบรวมได้ แต่แน่นอนว่าจะไม่ทำสิ่งที่คุณต้องการ
David Thornley

3

ในสตริง c ++ ไม่ใช่พลเมืองชั้นหนึ่ง การดำเนินการของสตริงจะกระทำผ่านไลบรารีมาตรฐาน ฉันคิดว่านั่นคือเหตุผล นอกจากนี้ C ++ ใช้การเพิ่มประสิทธิภาพตารางสาขาเพื่อปรับคำสั่งกรณีที่สวิตช์ ดูที่ลิงค์

http://en.wikipedia.org/wiki/Switch_statement


2

ใน C ++ คุณสามารถใช้คำสั่ง switch กับ int และ char เท่านั้น


3
ถ่านกลายเป็น int เช่นกัน
แปลกหน้า

พอยน์เตอร์ก็สามารถทำได้เช่นกัน นั่นหมายความว่าบางครั้งคุณสามารถรวบรวมสิ่งที่จะทำให้รู้สึกในภาษาที่แตกต่างกัน แต่มันจะไม่ทำงาน
David Thornley

จริงๆคุณสามารถใช้longและlong longที่จะไม่intกลายเป็น ไม่มีความเสี่ยงจากการถูกตัดทอนที่นั่น
MSalters


0
    cout << "\nEnter word to select your choice\n"; 
    cout << "ex to exit program (0)\n";     
    cout << "m     to set month(1)\n";
    cout << "y     to set year(2)\n";
    cout << "rm     to return the month(4)\n";
    cout << "ry     to return year(5)\n";
    cout << "pc     to print the calendar for a month(6)\n";
    cout << "fdc      to print the first day of the month(1)\n";
    cin >> c;
    cout << endl;
    a = c.compare("ex") ?c.compare("m") ?c.compare("y") ? c.compare("rm")?c.compare("ry") ? c.compare("pc") ? c.compare("fdc") ? 7 : 6 :  5  : 4 : 3 : 2 : 1 : 0;
    switch (a)
    {
        case 0:
            return 1;

        case 1:                   ///m
        {
            cout << "enter month\n";
            cin >> c;
            cout << endl;
            myCalendar.setMonth(c);
            break;
        }
        case 2:
            cout << "Enter year(yyyy)\n";
            cin >> y;
            cout << endl;
            myCalendar.setYear(y);
            break;
        case 3:
             myCalendar.getMonth();
            break;
        case 4:
            myCalendar.getYear();
        case 5:
            cout << "Enter month and year\n";
            cin >> c >> y;
            cout << endl;
            myCalendar.almanaq(c,y);
            break;
        case 6:
            break;

    }

4
ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
เบ็นจามินดับเบิลยู.

0

ในหลายกรณีคุณสามารถหางานพิเศษได้โดยดึงอักขระตัวแรกจากสตริงและสลับไปที่ อาจจบลงด้วยการทำสลับซ้อนบน charat (1) ถ้ากรณีของคุณเริ่มต้นด้วยค่าเดียวกัน ทุกคนที่อ่านรหัสของคุณจะขอบคุณคำใบ้ว่าเพราะส่วนใหญ่จะเป็นปัญหาถ้า - อื่น - ถ้า


0

วิธีแก้ปัญหาการทำงานที่มากขึ้นสำหรับปัญหาสวิตช์:

class APIHandlerImpl
{

// define map of "cases"
std::map<string, std::function<void(server*, websocketpp::connection_hdl, string)>> in_events;

public:
    APIHandlerImpl()
    {
        // bind handler method in constructor
        in_events["/hello"] = std::bind(&APIHandlerImpl::handleHello, this, _1, _2, _3);
        in_events["/bye"] = std::bind(&APIHandlerImpl::handleBye, this, _1, _2, _3);
    }

    void onEvent(string event = "/hello", string data = "{}")
    {
        // execute event based on incomming event
        in_events[event](s, hdl, data);
    }

    void APIHandlerImpl::handleHello(server* s, websocketpp::connection_hdl hdl, string data)
    {
        // ...
    }

    void APIHandlerImpl::handleBye(server* s, websocketpp::connection_hdl hdl, string data)
    {
        // ...
    }
}

-1

คุณไม่สามารถใช้สตริงในกรณีที่สลับได้อนุญาตให้ใช้เฉพาะ & อักขระภายในเท่านั้น แต่คุณสามารถลองใช้ enum เพื่อแทนค่าสตริงและใช้ในบล็อกตัวเรือนสวิตช์ได้

enum MyString(raj,taj,aaj);

ใช้มันในคำสั่งกรณี swich



-1

สวิทช์ใช้งานได้กับประเภทที่สำคัญเท่านั้น (int, char, bool, ฯลฯ ) ทำไมไม่ใช้แผนที่จับคู่สตริงกับตัวเลขแล้วใช้ตัวเลขนั้นกับสวิตช์?


-2

นั่นเป็นเพราะ C ++ เปลี่ยนสวิตช์เป็นตารางกระโดด มันทำการดำเนินการเล็กน้อยบนข้อมูลอินพุตและข้ามไปยังที่อยู่ที่เหมาะสมโดยไม่ต้องเปรียบเทียบ เนื่องจากสตริงไม่ใช่ตัวเลข แต่อาร์เรย์ของตัวเลข C ++ จึงไม่สามารถสร้างตารางการกระโดดได้

movf    INDEX,W     ; move the index value into the W (working) register from memory
addwf   PCL,F       ; add it to the program counter. each PIC instruction is one byte
                    ; so there is no need to perform any multiplication. 
                    ; Most architectures will transform the index in some way before 
                    ; adding it to the program counter

table                   ; the branch table begins here with this label
    goto    index_zero  ; each of these goto instructions is an unconditional branch
    goto    index_one   ; of code
    goto    index_two
    goto    index_three

index_zero
    ; code is added here to perform whatever action is required when INDEX = zero
    return

index_one
...

(รหัสจากวิกิพีเดียhttps://en.wikipedia.org/wiki/Branch_table )


4
C ++ ไม่ต้องการการใช้งานไวยากรณ์ใด ๆ โดยเฉพาะ ไร้เดียงสาcmp/ jccการใช้งานสามารถใช้ได้ตามมาตรฐาน C ++
Ruslan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.