मेरे पास संकलन समय पर चार सरणी द्वारा दर्शाए गए फ़ील्ड की अल्पविराम से अलग सूची है:

constexpr static char arrayStr[] = "a,b,c";

मैं "," पर विभाजित करना चाहता हूं और संकलन समय पर उपलब्ध तत्वों की संख्या रखना चाहता हूं। छद्म कोड:

constexpr static size_t numFields = SPLIT(arrayStr, ",");

3 वापस आ जाएगा।

क्या सी ++ 17 का उपयोग करके इसे हासिल करने का कोई तरीका है?

8
user997112 1 अक्टूबर 2019, 01:03
Constexpr फ़ंक्शन में बस ',' को गिनें। C++17 . में आसान
 – 
doug
1 अक्टूबर 2019, 01:18

2 जवाब

सबसे बढ़िया उत्तर

एक टेम्पलेट फ़ंक्शन का उपयोग करना जो संदर्भ द्वारा एक निश्चित लंबाई सरणी को स्वीकार करता है, सरणी की लंबाई पर टेम्पलेट किया जाता है:

#include <iostream>
#include <array>

constexpr char arrayStr[] = "a,b,c";

template<size_t N>
constexpr size_t numFields(const char(&arrayStr)[N], char delim) {
    size_t count = 1;
    for (const auto& ch : arrayStr) {
        if (ch == delim) {
            ++count;
        }
    }
    return count;
}

using namespace std;
int main(int argc, char *argv[]) {
    array<string,numFields(arrayStr,',')> x;
    cout << x.size() << endl;
}

अस्थायी तीर arrayStr एक निश्चित आकार के सरणी तर्क होने के लिए, सीमा-आधारित लूप की अनुमति देता है।

संपादित करें

ओपी ने टिप्पणियों में संकलन समय पर एक वर्ग बनाने के बारे में पूछा, जिसके सदस्यों में स्ट्रिंग शाब्दिक और इसकी टोकननाइज़ेशन गिनती शामिल है (स्थिर वर्ग के सदस्यों के बारे में कुछ भी उल्लेख किया गया था, लेकिन मैं उपयोग के मामले पर स्पष्ट नहीं हूं)। यह अधिक पेचीदा था! कुछ काम के बाद, उपरोक्त numFields फ़ंक्शन का उपयोग कुछ इस तरह से किया जा सकता है:

class Foo {
public:
    template<typename T>
    constexpr Foo(T&& str, char delim)
    : _array(std::forward<T>(str)),
      _count(numFields(_array,delim)) {
    }

    auto data() const {
        return _array;
    }

    size_t size() const {
        return _count;
    }

private:
    const char (&_array)[N];
    const size_t _count;
};


template<typename T>
constexpr auto wrapArray(T&& str, char delim) -> Foo<sizeof(str)> {
    return Foo<sizeof(str)>(std::forward<T>(str),delim);
}

constexpr auto wrappedArrayStr = wrapArray("a,b,c",',');

using namespace std;
int main(int argc, char *argv[]) {
    cout << wrappedArrayStr.size() << endl;
    cout << wrappedArrayStr.data() << endl;
}

मुझे यकीन नहीं है कि यहां सही अग्रेषण जरूरी है, लेकिन मैं कक्षा के सदस्य को स्ट्रिंग शाब्दिक तर्क को अग्रेषित करने के लिए इसका उपयोग करता हूं। हेल्पर फंक्शन wrapArray सभी कंपाइल टाइम स्ट्रिंग लिटरल को डबल-पेस्ट करने से रोकता है, यानी constexpr Foo<sizeof("a,b,c")> wrappedArrayStr("a,b,c",','); से बचना।

1
jwimberley 1 अक्टूबर 2019, 05:10
क्या यह एक constexpr स्थिर size_t वर्ग सदस्य को अनुमति देता है?
 – 
user997112
1 अक्टूबर 2019, 01:28
पक्का नहीं आपका क्या मतलब है? वापसी मान constexpr size_t है, और std::array में उपयोग यह साबित करता है।
 – 
jwimberley
1 अक्टूबर 2019, 01:31
यह संकलक त्रुटियों को कह रहा है कि numFields को निरंतर अभिव्यक्ति के रूप में उपयोग नहीं किया जा सकता है। arrayStr और तत्वों की संख्या एक ही वर्ग के दोनों वर्ग के सदस्य हैं?
 – 
user997112
1 अक्टूबर 2019, 01:36
आपका क्लास कंस्ट्रक्टर कैसा दिखता है?
 – 
jwimberley
1 अक्टूबर 2019, 01:46

मैं चार सरणी को स्ट्रिंग में कनवर्ट करना चाहता हूं, फिर "," पर विभाजित करना चाहता हूं और संकलन समय पर उपलब्ध तत्वों की संख्या रखना चाहता हूं।

यदि "स्ट्रिंग" के लिए आपका मतलब "std::string" है, तो यह constexpr नहीं है, इसलिए यह संकलन समय गणना के साथ असंगत है।

यदि "स्ट्रिंग" के लिए आप सी-स्टाइल स्ट्रिंग, एक char const * स्वीकार करते हैं, और यदि आप एकल char के विभाजकों में रुचि रखते हैं, तो आप कुछ इस प्रकार आजमा सकते हैं

#include <iostream>

constexpr static char arrayStr[] = "a,b,c";

constexpr std::size_t SPLIT (char const * str, char sep)
 {
   std::size_t  ret { 1u };

   while ( *str )
      if ( sep == *str++ )
         ++ ret;

   return ret;
 }

int main ()
 {
   constexpr auto numFields = SPLIT(arrayStr, ',');

   std::cout << numFields << std::endl;  // print 3
 }
4
max66 1 अक्टूबर 2019, 01:18
जब मैं SPLIT () को numFields पर असाइन करता हूं तो मुझे "constexpr वैरिएबल 'numFields' को निरंतर अभिव्यक्ति द्वारा प्रारंभ किया जाना चाहिए"
 – 
user997112
1 अक्टूबर 2019, 01:33
1
- मुझे नहीं पता कि आपकी समस्या कहां है ... मेरे उत्तर में कोड जी ++ (8.3.0) और क्लैंग ++ (7.0.1) दोनों के साथ संकलित है। आप मेरा सटीक कोड संकलित कर रहे हैं? आप किस कंपाइलर का उपयोग कर रहे हैं? क्या आप सी ++ 17 संकलित कर रहे हैं? (लेकिन सी ++ 14 पर्याप्त होना चाहिए)
 – 
max66
1 अक्टूबर 2019, 01:36
क्या आप इन्हें कक्षा में रख सकते हैं, एक नया सदस्य बना सकते हैं: constexpr static size_t numElements = SPLIT(arrayStr, ',');
 – 
user997112
1 अक्टूबर 2019, 01:38
1
- क्यों नहीं? class foo { public: static constexpr auto bar = SPLIT(arrayStr, ','); };
 – 
max66
1 अक्टूबर 2019, 01:40
मैंने दूसरे उत्तर का उपयोग किया, लेकिन मैंने आपको तीन अपवोट दिए हैं क्योंकि आपने पहले उत्तर दिया था
 – 
user997112
1 अक्टूबर 2019, 01:46