วิธีการเริ่มต้นสมาชิกคงที่ส่วนตัวใน C ++?


519

วิธีที่ดีที่สุดในการเริ่มต้นสมาชิกข้อมูลส่วนตัวแบบคงที่ใน C ++ คืออะไร? ฉันลองสิ่งนี้ในไฟล์ส่วนหัวของฉัน แต่มันทำให้ฉันมีข้อผิดพลาด linker:

class foo
{
    private:
        static int i;
};

int foo::i = 0;

ฉันเดาว่าเป็นเพราะฉันไม่สามารถเริ่มสมาชิกส่วนตัวจากนอกห้องเรียนได้ ดังนั้นวิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?


2
สวัสดีเจสัน ฉันไม่พบความคิดเห็นเกี่ยวกับการเริ่มต้นสมาชิกแบบคงที่ (โดยเฉพาะสมาชิกที่สำคัญ) ในความเป็นจริงคุณต้องเขียน int foo :: i เพื่อให้ linker สามารถค้นหาได้ แต่มันจะเริ่มต้นโดยอัตโนมัติด้วย 0! บรรทัดนี้จะเพียงพอ: int foo :: i; (สิ่งนี้ใช้ได้สำหรับวัตถุทั้งหมดที่เก็บไว้ในหน่วยความจำแบบคงที่ตัวเชื่อมโยงจะรับผิดชอบในการเริ่มต้นวัตถุแบบคงที่)
Nico

1
คำตอบด้านล่างใช้ไม่ได้กับคลาสเทมเพลต พวกเขากล่าวว่า: การเริ่มต้นจะต้องเข้าไปในไฟล์ต้นฉบับ สำหรับคลาสเทมเพลตนี่เป็นไปไม่ได้และไม่จำเป็น
Joachim W

7
C ++ 17 ช่วยให้การเริ่มต้นอินไลน์สมาชิกข้อมูลแบบคงที่ inline static int x[] = {1, 2, 3};(แม้ชนิดที่ไม่ใช่จำนวนเต็ม): ดูen.cppreference.com/w/cpp/language/static#Static_data_members
Vladimir Reshetnikov

คำตอบ:


556

การประกาศคลาสควรอยู่ในไฟล์ส่วนหัว (หรือในไฟล์ต้นฉบับหากไม่ได้แชร์)
ไฟล์: foo.h

class foo
{
    private:
        static int i;
};

แต่การเริ่มต้นควรอยู่ในไฟล์ต้นฉบับ
ไฟล์: foo.cpp

int foo::i = 0;

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

หมายเหตุ:แมตต์เคอร์ติ: ชี้ให้เห็นว่า C ++ ช่วยให้เข้าใจง่ายของข้างต้นถ้าตัวแปรสมาชิกคงเป็นชนิด int const (เช่นint, bool, char) จากนั้นคุณสามารถประกาศและเริ่มต้นตัวแปรสมาชิกโดยตรงภายในการประกาศคลาสในไฟล์ส่วนหัว:

class foo
{
    private:
        static int const i = 42;
};

4
ใช่. แต่ฉันสมมติว่าคำถามได้ง่ายขึ้น ในทางเทคนิคแล้วการประกาศและการกำหนดสามารถอยู่ในไฟล์ต้นฉบับไฟล์เดียว แต่นั่นก็ จำกัด การใช้คลาสโดยคลาสอื่น
Martin York

11
จริง ๆ แล้วไม่ใช่แค่ POD มันต้องเป็น int type ด้วยเช่นกัน (int, short, bool, char ... )
Matt Curtis

9
โปรดทราบว่านี่ไม่ใช่แค่คำถามว่าค่าเริ่มต้นได้อย่างไร: const integral type ที่กำหนดเช่นนี้อาจเปลี่ยนเป็นค่าคงที่เวลาคอมไพล์โดยการใช้งาน สิ่งนี้ไม่ใช่สิ่งที่คุณต้องการเสมอไปเนื่องจากเป็นการเพิ่มการพึ่งพาไบนารี: รหัสลูกค้าต้องการการคอมไพล์ใหม่หากค่าเปลี่ยนแปลง
Steve Jessop

5
@ มาร์ติน: นอกเหนือจากการแก้ไข s / POD / อินทิกรัลชนิด / หากที่อยู่เคยถูกถ่ายแล้วก็จำเป็นต้องมีคำจำกัดความด้วย แปลกอย่างที่มันฟังดูการประกาศด้วย initializer ในการกำหนดคลาสไม่ใช่คำจำกัดความ สำนวน const เทมเพลตให้วิธีแก้ปัญหาสำหรับกรณีที่คุณต้องการความละเอียดในไฟล์ส่วนหัวที่ วิธีแก้ไขอื่นที่ง่ายกว่าคือฟังก์ชันที่สร้างค่าของค่าคงที่แบบคงที่ ไชโย & hth.
ไชโยและ hth - Alf

3
คุณอาจเพิ่มความกระจ่างที่ int foo :: i = 0; ไม่ควรอยู่ในฟังก์ชั่น (รวมถึงฟังก์ชั่นหลัก) ฉันมีมันในตอนต้นของฟังก์ชั่นหลักของฉันและมันก็ไม่เป็นเช่นนั้น
qwerty9967

89

สำหรับตัวแปร :

foo.h:

class foo
{
private:
    static int i;
};

foo.cpp:

int foo::i = 0;

นี่เป็นเพราะfoo::iโปรแกรมของคุณมีได้เพียงอินสแตนซ์เดียวเท่านั้น มันคล้ายกับextern int iในไฟล์ส่วนหัวและint iในไฟล์ต้นฉบับ

สำหรับค่าคงที่คุณสามารถใส่ค่าลงไปในการประกาศคลาสได้:

class foo
{
private:
    static int i;
    const static int a = 42;
};

2
นี่คือจุดที่ถูกต้อง ฉันจะเพิ่มคำอธิบายของฉันด้วย แต่ควรสังเกตว่าสิ่งนี้ใช้ได้กับประเภท POD เท่านั้น
Martin York

ตั้งแต่เมื่อ C ++ อนุญาตให้ทำได้ดีด้วยการประกาศในคลาสและไม่มีคำนิยามสำหรับประเภทอินทิกรัล ตั้งแต่ C ++ 98 เองหรือ C ++ 03 หรือเมื่อไหร่? กรุณาแบ่งปันลิงค์ของแท้โปรด ถ้อยคำมาตรฐาน C ++ ไม่ได้ซิงค์กับคอมไพเลอร์ พวกเขากล่าวถึงสมาชิกจะยังคงกำหนดถ้าพวกเขาใช้ ดังนั้นฉันไม่ต้องการการอ้างอิงมาตรฐาน C ++
smRaj

1
ฉันสงสัยว่าทำไมprivateตัวแปรสามารถเริ่มต้นนอกคลาสได้ที่นี่สามารถทำได้สำหรับตัวแปรที่ไม่คงที่เช่นกัน
กฤษณะ Oza

คุณพบคำอธิบายหรือไม่? @Krishna_Oza
nn0p

@ nn0p ยังไม่ได้ แต่การเริ่มต้นตัวแปรส่วนตัวแบบคงที่นอกClassไม่ได้ทำให้รู้สึกใน Cpp
กฤษณะ Oza

41

ตั้งแต่ C ++ 17 สมาชิกแบบคงที่อาจถูกกำหนดในส่วนหัวด้วยคำหลักแบบอินไลน์

http://en.cppreference.com/w/cpp/language/static

"สมาชิกข้อมูลแบบคงที่อาจประกาศแบบอินไลน์สมาชิกข้อมูลแบบคงที่แบบอินไลน์สามารถกำหนดไว้ในคำจำกัดความของชั้นเรียนและอาจระบุสมาชิกเริ่มต้นเริ่มต้นมันไม่จำเป็นต้องมีคำนิยามนอกชั้น:"

struct X
{
    inline static int n = 1;
};

1
สิ่งนี้เป็นไปได้ตั้งแต่ C ++ 17 ซึ่งขณะนี้อยู่ในระหว่างดำเนินการกลายเป็นมาตรฐานใหม่
Grebu

31

สำหรับผู้ชมในอนาคตของคำถามนี้ผมอยากจะชี้ให้เห็นว่าคุณควรหลีกเลี่ยงสิ่งที่monkey0506 จะแนะนำ

ไฟล์ส่วนหัวใช้สำหรับการประกาศ

ไฟล์ส่วนหัวได้รับการรวบรวมหนึ่งครั้งสำหรับทุก.cppไฟล์ที่โดยตรงหรือโดยอ้อม#includesและโค้ดนอกฟังก์ชั่นใด ๆ จะถูกเรียกใช้เมื่อเริ่มต้นโปรแกรมก่อนหน้าmain()นี้

โดยใส่: foo::i = VALUE;ลงในส่วนหัวfoo:iจะได้รับการกำหนดค่าVALUE(สิ่งที่เป็น) สำหรับทุก.cppไฟล์และการมอบหมายเหล่านี้จะเกิดขึ้นในลำดับที่ไม่แน่นอน (กำหนดโดย linker) ก่อนที่จะmain()ถูกเรียกใช้

ถ้าหากเรา#define VALUEเป็นหมายเลขที่แตกต่างกันใน.cppไฟล์ใดไฟล์หนึ่งของเรา มันจะรวบรวมข้อมูลที่ดีและเราจะไม่มีทางรู้ว่าจะมีใครชนะจนกว่าเราจะเรียกใช้โปรแกรม

อย่าใส่โค้ดที่เรียกใช้งานลงในส่วนหัวด้วยเหตุผลเดียวกับที่คุณไม่เคย#includeมี.cppไฟล์

รวมถึงยาม (ซึ่งฉันเห็นด้วยกับที่คุณควรใช้) ปกป้องคุณจากสิ่งที่แตกต่าง: ส่วนหัวเดียวกันถูกอ้อม#includeหลายครั้งในขณะที่รวบรวม.cppไฟล์เดียว


2
คุณพูดถูกเกี่ยวกับเรื่องนี้ยกเว้นในกรณีของเทมเพลตชั้นเรียน (ซึ่งไม่ได้ถูกถาม ดังนั้นหากคลาสนั้นถูกกำหนดอย่างสมบูรณ์และไม่ใช่เทมเพลตคลาสให้ใส่สมาชิกแบบสแตติกเหล่านี้ในไฟล์ CPP แยกต่างหาก แต่สำหรับเทมเพลตคลาสคำจำกัดความต้องอยู่ในหน่วยการแปลเดียวกัน (เช่นไฟล์ส่วนหัว)
monkey0506

@ monkey_05_06: นั่นเป็นเพียงข้อโต้แย้งเพื่อหลีกเลี่ยงการเป็นสมาชิกแบบคงที่ในรหัสเทมเพลต: คุณได้จบลงด้วยสมาชิกแบบคงที่หนึ่งรายสำหรับแต่ละอินสแตนซ์ของชั้นเรียน ปัญหาแย่ลงโดยอาจรวบรวมส่วนหัวเป็นไฟล์ cpp หลายไฟล์ ... คุณอาจได้คำนิยามที่ขัดแย้งกัน
Joshua Clayton

publib.boulder.ibm.com/infocenter/macxhelp/v6v81/…ลิงก์นี้แสดงให้เห็นถึงสมาชิกเทมเพลตคงที่ซึ่งมีฟังก์ชั่นหลักซึ่งสะอาดกว่าหากเป็นภาระ
Joshua Clayton

1
ข้อโต้แย้งของคุณกว้างใหญ่มาก ก่อนอื่นคุณไม่สามารถ #define VALUE ได้เนื่องจากชื่อแมโครมี ot เป็นตัวระบุที่ถูกต้อง และแม้ว่าคุณจะทำได้ - ใครจะทำเช่นนั้น? ไฟล์ส่วนหัวใช้สำหรับการประกาศ -? C'mon .. กรณีเดียวที่คุณควรหลีกเลี่ยงการใส่ค่าในส่วนหัวคือต่อสู้กับ odr-used และการใส่ค่าในส่วนหัวอาจนำไปสู่การรวบรวมซ้ำที่ไม่จำเป็นเมื่อใดก็ตามที่คุณต้องการเปลี่ยนค่า
Aleksander Fular

20

ด้วยคอมไพเลอร์ไมโครซอฟท์ [1], ตัวแปรคงที่ไม่intเหมือนยังสามารถกำหนดไว้ในแฟ้มส่วนหัว __declspec(selectany)แต่อยู่นอกการประกาศคลาสโดยใช้เฉพาะไมโครซอฟท์

class A
{
    static B b;
}

__declspec(selectany) A::b;

โปรดทราบว่าฉันไม่ได้บอกว่าสิ่งนี้ดีฉันแค่บอกว่าสามารถทำได้

[1] ทุกวันนี้คอมไพเลอร์มากกว่าการสนับสนุน MSC __declspec(selectany)- อย่างน้อย gcc และเสียงดังกราว อาจจะมากกว่านั้น


17
int foo::i = 0; 

เป็นไวยากรณ์ที่ถูกต้องสำหรับการเริ่มต้นตัวแปร แต่ต้องอยู่ในไฟล์ต้นฉบับ (.cpp) แทนที่จะอยู่ในส่วนหัว

เนื่องจากมันเป็นตัวแปรแบบคงที่คอมไพเลอร์จำเป็นต้องสร้างสำเนาเดียวเท่านั้น คุณต้องมีบรรทัด "int foo: i" บางอย่างที่ในรหัสของคุณเพื่อบอกคอมไพเลอร์ที่จะวางไว้มิฉะนั้นคุณจะได้รับข้อผิดพลาดลิงค์ หากอยู่ในส่วนหัวคุณจะได้รับสำเนาในทุกไฟล์ที่มีส่วนหัวดังนั้นรับข้อผิดพลาดสัญลักษณ์ที่กำหนดทวีคูณจาก linker


12

ฉันมีตัวแทนไม่เพียงพอที่นี่เพื่อเพิ่มเป็นความคิดเห็น แต่ IMO เป็นสไตล์ที่ดีในการเขียนส่วนหัวของคุณด้วยยาม #includeอย่างไรก็ตามซึ่งสังเกตโดย Paranaix ไม่กี่ชั่วโมงที่ผ่านมาจะป้องกันข้อผิดพลาดหลายคำนิยาม หากคุณไม่ได้ใช้ไฟล์ CPP แยกกันอยู่แล้วคุณไม่จำเป็นต้องใช้ไฟล์ใดไฟล์หนึ่งในการเริ่มต้นสมาชิกแบบสแตติกที่ไม่ใช่อินทิกรัล

#ifndef FOO_H
#define FOO_H
#include "bar.h"

class foo
{
private:
    static bar i;
};

bar foo::i = VALUE;
#endif

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


21
#include guards เพียงป้องกันหลายคำจำกัดความต่อหน่วยการแปล
Paul Fultz II

3
เกี่ยวกับสไตล์ที่ดี: คุณควรเพิ่มความคิดเห็นในตอนท้ายของการปิด:#endif // FOO_H
ริกา

9
ใช้งานได้เฉพาะในกรณีที่คุณมีหน่วยคอมไพล์เดียวที่มี foo.h หากสอง cpps อย่างน้อยหนึ่งอันรวมถึง foo.h ซึ่งเป็นสถานการณ์ทั่วไปแต่ละ cpp จะประกาศตัวแปรคงที่เดียวกันดังนั้น linker จะบ่นกับคำนิยามหลายคำของ `foo :: i 'เว้นแต่คุณจะใช้การรวบรวมแพ็คเกจกับไฟล์ (รวบรวม ไฟล์เดียวเท่านั้นที่มี cpps ทั้งหมด) แต่ถึงแม้ว่าการคอมไพล์แพ็กเกจจะดีมากวิธีแก้ปัญหาก็คือการประกาศ (int foo :: i = 0;) ใน cpp!
Alejadro Xalabarder

1
หรือใช้เพียง#pragma once
59

12

หากคุณต้องการเริ่มต้นชนิดผสม (สตริง fe) บางอย่างคุณสามารถทำสิ่งนี้:

class SomeClass {
  static std::list<string> _list;

  public:
    static const std::list<string>& getList() {
      struct Initializer {
         Initializer() {
           // Here you may want to put mutex
           _list.push_back("FIRST");
           _list.push_back("SECOND");
           ....
         }
      }
      static Initializer ListInitializationGuard;
      return _list;
    }
};

เนื่องจากListInitializationGuardเป็นตัวแปรสแตติกภายในSomeClass::getList()วิธีมันจะถูกสร้างเพียงครั้งเดียวซึ่งหมายความว่าคอนสตรัคที่เรียกว่าครั้งเดียว สิ่งนี้จะinitialize _listผันแปรตามมูลค่าที่คุณต้องการ การเรียกที่ตามมาใด ๆgetListจะส่งคืน_listวัตถุที่เริ่มต้นแล้ว

แน่นอนคุณต้องเข้าถึง_listวัตถุเสมอโดยgetList()วิธีการโทร


1
นี่คือรุ่นของสำนวนนี้ที่ไม่จำเป็นต้องสร้างวิธีหนึ่งต่อวัตถุสมาชิก: stackoverflow.com/a/48337288/895245
Ciro Santilli 法轮功冠状冠状病六四事件法轮功

9

รูปแบบตัวสร้างสแตติก C ++ 11 ที่ทำงานสำหรับวัตถุหลายรายการ

มีการเสนอสำนวนหนึ่งที่: https://stackoverflow.com/a/27088552/895245แต่ที่นี่จะเป็นเวอร์ชั่นที่สะอาดกว่าซึ่งไม่จำเป็นต้องสร้างวิธีการใหม่ต่อสมาชิก

main.cpp

#include <cassert>
#include <vector>

// Normally on the .hpp file.
class MyClass {
public:
    static std::vector<int> v, v2;
    static struct StaticConstructor {
        StaticConstructor() {
            v.push_back(1);
            v.push_back(2);
            v2.push_back(3);
            v2.push_back(4);
        }
    } _staticConstructor;
};

// Normally on the .cpp file.
std::vector<int> MyClass::v;
std::vector<int> MyClass::v2;
// Must come after every static member.
MyClass::StaticConstructor MyClass::_staticConstructor;

int main() {
    assert(MyClass::v[0] == 1);
    assert(MyClass::v[1] == 2);
    assert(MyClass::v2[0] == 3);
    assert(MyClass::v2[1] == 4);
}

GitHub ต้นน้ำ

รวบรวมและเรียกใช้:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

ดูเพิ่มเติมที่: ตัวสร้างแบบคงที่ใน C ++? ฉันต้องเริ่มต้นวัตถุคงที่ส่วนตัว

ทดสอบบน Ubuntu 19.04

ตัวแปรอินไลน์ C ++ 17

พูดถึงที่: https://stackoverflow.com/a/45062055/895245แต่นี่คือตัวอย่างที่สามารถรันได้แบบมัลติไฟล์เพื่อให้ชัดเจนยิ่งขึ้น: ตัวแปรอินไลน์ทำงานอย่างไร


5

คุณยังสามารถรวมการกำหนดไว้ในไฟล์ส่วนหัวได้หากคุณใช้การ์ดส่วนหัว ฉันใช้เทคนิคนี้สำหรับไลบรารี C ++ ที่ฉันสร้างขึ้น อีกวิธีหนึ่งในการบรรลุผลลัพธ์เดียวกันคือการใช้วิธีการคงที่ ตัวอย่างเช่น...

class Foo
   {
   public:
     int GetMyStatic() const
     {
       return *MyStatic();
     }

   private:
     static int* MyStatic()
     {
       static int mStatic = 0;
       return &mStatic;
     }
   }

โค้ดด้านบนมี "โบนัส" ที่ไม่ต้องการ CPP / ไฟล์ต้นฉบับ อีกวิธีที่ฉันใช้สำหรับไลบรารี C ++ ของฉัน


4

ฉันทำตามความคิดจากคาร์ล ฉันชอบมันและตอนนี้ฉันก็ใช้มันเช่นกัน ฉันเปลี่ยนสัญกรณ์เล็กน้อยแล้วเพิ่มฟังก์ชั่นบางอย่าง

#include <stdio.h>

class Foo
{
   public:

     int   GetMyStaticValue () const {  return MyStatic();  }
     int & GetMyStaticVar ()         {  return MyStatic();  }
     static bool isMyStatic (int & num) {  return & num == & MyStatic(); }

   private:

      static int & MyStatic ()
      {
         static int mStatic = 7;
         return mStatic;
      }
};

int main (int, char **)
{
   Foo obj;

   printf ("mystatic value %d\n", obj.GetMyStaticValue());
   obj.GetMyStaticVar () = 3;
   printf ("mystatic value %d\n", obj.GetMyStaticValue());

   int valMyS = obj.GetMyStaticVar ();
   int & iPtr1 = obj.GetMyStaticVar ();
   int & iPtr2 = valMyS;

   printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}

ผลลัพธ์นี้

mystatic value 7
mystatic value 3
is my static 1 0

3

ยังทำงานในไฟล์ privateStatic.cpp:

#include <iostream>

using namespace std;

class A
{
private:
  static int v;
};

int A::v = 10; // possible initializing

int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}

// g++ privateStatic.cpp -o privateStatic && ./privateStatic

3

set_default()วิธีการเกี่ยวกับอะไร?

class foo
{
    public:
        static void set_default(int);
    private:
        static int i;
};

void foo::set_default(int x) {
    i = x;
}

เราจะต้องใช้set_default(int x)วิธีการและstaticตัวแปรของเราจะเริ่มต้นได้

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


3

ปัญหาตัวเชื่อมโยงที่คุณพบอาจเกิดจาก:

  • ให้ทั้งนิยามคลาสและสมาชิกสแตติกในไฟล์ส่วนหัว
  • การรวมส่วนหัวนี้ในซอร์สไฟล์สองไฟล์ขึ้นไป

นี่เป็นปัญหาที่พบบ่อยสำหรับผู้ที่เริ่มต้นด้วย C ++ สมาชิกคลาสแบบสแตติกต้องเริ่มต้นในหน่วยการแปลเดียวเช่นในไฟล์ต้นฉบับเดียว

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

class Foo
{
    // int& getObjectInstance() const {
    static int& getObjectInstance() {
        static int object;
        return object;
    }

    void func() {
        int &object = getValueInstance();
        object += 5;
    }
};

1
ฉันยังคงเป็น n00b สมบูรณ์ตราบใดที่ C ++ ไป แต่สิ่งนี้ดูยอดเยี่ยมสำหรับฉันขอบคุณมาก! ฉันได้รับการจัดการวงจรชีวิตที่สมบูรณ์แบบของวัตถุซิงเกิลฟรี
Rafael Kitover

2

วิธีหนึ่งในการกำหนดค่าคงที่คือ "โรงเรียนเก่า" คือการแทนที่ด้วยenum:

class foo
{
    private:
        enum {i = 0}; // default type = int
        enum: int64_t {HUGE = 1000000000000}; // may specify another type
};

วิธีนี้ไม่จำเป็นต้องให้คำนิยามและหลีกเลี่ยงการทำอย่างต่อเนื่องlvalueซึ่งสามารถช่วยให้คุณประหยัดปวดหัวบางเช่นเมื่อคุณตั้งใจODR ใช้มัน


1

ฉันแค่อยากจะพูดถึงบางสิ่งที่แปลกเล็กน้อยสำหรับฉันเมื่อฉันพบสิ่งนี้เป็นครั้งแรก

ฉันต้องการเริ่มต้นสมาชิกข้อมูลสแตติกส่วนตัวในคลาสเทมเพลต

ใน. h หรือ. hpp ดูเหมือนว่านี่เพื่อเริ่มต้นสมาชิกข้อมูลคงที่ของคลาสเทมเพลต:

template<typename T>
Type ClassName<T>::dataMemberName = initialValue;

0

สิ่งนี้ทำหน้าที่ของคุณหรือไม่

//header file

struct MyStruct {
public:
    const std::unordered_map<std::string, uint32_t> str_to_int{
        { "a", 1 },
        { "b", 2 },
        ...
        { "z", 26 }
    };
    const std::unordered_map<int , std::string> int_to_str{
        { 1, "a" },
        { 2, "b" },
        ...
        { 26, "z" }
    };
    std::string some_string = "justanotherstring";  
    uint32_t some_int = 42;

    static MyStruct & Singleton() {
        static MyStruct instance;
        return instance;
    }
private:
    MyStruct() {};
};

//Usage in cpp file
int main(){
    std::cout<<MyStruct::Singleton().some_string<<std::endl;
    std::cout<<MyStruct::Singleton().some_int<<std::endl;
    return 0;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.