Aracılığıyla paylaş


Kullanıcı tanımlı sabit değerler

C++'da altı ana değişmez değer kategorisi vardır: tamsayı, karakter, kayan nokta, dize, boole ve işaretçi. C++11'den başlayarak, yaygın deyimler için söz dizimsel kısayollar sağlamak ve tür güvenliğini artırmak için bu kategorilere göre kendi değişmez değerlerinizi tanımlayabilirsiniz. Örneğin, bir Distance sınıfınız olduğunu varsayalım. Kilometreler için bir değişmez değer ve kilometreler için başka bir sabit değer tanımlayabilir ve kullanıcıyı ölçü birimleri hakkında açık olmaya teşvik etmek için şunu yazabilirsiniz: auto d = 42.0_km veya auto d = 42.0_mi. Kullanıcı tanımlı değişmez değerlerin performans avantajı veya dezavantajı yoktur; bunlar öncelikli olarak kolaylık sağlamak veya derleme zamanı türü kesintisi içindir. Standart Kitaplık, kron başlığındaki> zaman ve süre işlemlerindeki <birimler için , std::complexiçin ve için kullanıcı tanımlı değişmez değerlere std::stringsahiptir:

Distance d = 36.0_mi + 42.0_km;         // Custom UDL (see below)
std::string str = "hello"s + "World"s;  // Standard Library <string> UDL
complex<double> num =
   (2.0 + 3.01i) * (5.0 + 4.3i);        // Standard Library <complex> UDL
auto duration = 15ms + 42h;             // Standard Library <chrono> UDLs

Kullanıcı tanımlı değişmez işleç imzaları

Aşağıdaki formlardan biriyle ad alanı kapsamında "" işleci tanımlayarak kullanıcı tanımlı değişmez değer uygularsınız:

ReturnType operator "" _a(unsigned long long int);   // Literal operator for user-defined INTEGRAL literal
ReturnType operator "" _b(long double);              // Literal operator for user-defined FLOATING literal
ReturnType operator "" _c(char);                     // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _d(wchar_t);                  // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _e(char16_t);                 // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _f(char32_t);                 // Literal operator for user-defined CHARACTER literal
ReturnType operator "" _g(const char*, size_t);      // Literal operator for user-defined STRING literal
ReturnType operator "" _h(const wchar_t*, size_t);   // Literal operator for user-defined STRING literal
ReturnType operator "" _i(const char16_t*, size_t);  // Literal operator for user-defined STRING literal
ReturnType operator "" _g(const char32_t*, size_t);  // Literal operator for user-defined STRING literal
ReturnType operator "" _r(const char*);              // Raw literal operator
template<char...> ReturnType operator "" _t();       // Literal operator template

Önceki örnekteki işleç adları, sağladığınız adın yer tutucularıdır; ancak, baştaki alt çizgi gereklidir. (Yalnızca Standart Kitaplığın alt çizgi olmadan değişmez değerleri tanımlamasına izin verilir.) Dönüş türü, dönüştürmeyi veya değişmez değer tarafından yapılan diğer işlemleri özelleştirdiğiniz yerdir. Ayrıca, bu işleçlerden herhangi biri olarak constexprtanımlanabilir.

Pişmiş değişmez değerler

Kaynak kodunda, kullanıcı tanımlı olsun veya olmasın, herhangi bir değişmez değer temelde , veya 54.7"hello"truegibi 101alfasayısal karakter dizisidir. Derleyici, diziyi tamsayı, kayan, sabit karakter* dize vb. olarak yorumlar. Derleyicinin değişmez değere atanan türü ne olursa olsun giriş olarak kabul eden kullanıcı tanımlı değişmez değer, gayri resmi olarak pişmiş değişmez değer olarak bilinir. Ve dışında _r_t yukarıdaki tüm işleçler pişmiş değişmez değerlerdir. Örneğin, değişmez değer 42.0_km , _b benzer bir imzaya sahip _km adlı işleçe bağlanır ve değişmez değer 42_km de _a benzer bir imzaya sahip bir işleci bağlar.

Aşağıdaki örnekte, kullanıcı tanımlı değişmez değerlerin çağıranları girişleri hakkında açık olmaya nasıl teşvik edebildiği gösterilmektedir. oluşturmak Distanceiçin, kullanıcının uygun kullanıcı tanımlı değişmez değeri kullanarak açıkça kilometre veya mil belirtmesi gerekir. Aynı sonucu başka yollarla elde edebilirsiniz, ancak kullanıcı tanımlı değişmez değerler alternatiflerden daha az ayrıntılıdır.

// UDL_Distance.cpp

#include <iostream>
#include <string>

struct Distance
{
private:
    explicit Distance(long double val) : kilometers(val)
    {}

    friend Distance operator"" _km(long double val);
    friend Distance operator"" _mi(long double val);

    long double kilometers{ 0 };
public:
    const static long double km_per_mile;
    long double get_kilometers() { return kilometers; }

    Distance operator+(Distance other)
    {
        return Distance(get_kilometers() + other.get_kilometers());
    }
};

const long double Distance::km_per_mile = 1.609344L;

Distance operator"" _km(long double val)
{
    return Distance(val);
}

Distance operator"" _mi(long double val)
{
    return Distance(val * Distance::km_per_mile);
}

int main()
{
    // Must have a decimal point to bind to the operator we defined!
    Distance d{ 402.0_km }; // construct using kilometers
    std::cout << "Kilometers in d: " << d.get_kilometers() << std::endl; // 402

    Distance d2{ 402.0_mi }; // construct using miles
    std::cout << "Kilometers in d2: " << d2.get_kilometers() << std::endl;  //646.956

    // add distances constructed with different units
    Distance d3 = 36.0_mi + 42.0_km;
    std::cout << "d3 value = " << d3.get_kilometers() << std::endl; // 99.9364

    // Distance d4(90.0); // error constructor not accessible

    std::string s;
    std::getline(std::cin, s);
    return 0;
}

Değişmez değer sayısı ondalık kullanmalıdır. Aksi takdirde, sayı tamsayı olarak yorumlanır ve tür işleçle uyumlu olmaz. Kayan nokta girişi için türü, long doubleintegral türleri için ise olmalıdır long long.

Ham değişmez değerler

Ham kullanıcı tanımlı değişmez değerde, tanımladığınız işleç değişmez değeri bir karakter değerleri dizisi olarak kabul eder. Bu sırayı bir sayı, dize veya başka bir tür olarak yorumlamak size bağlı. Bu sayfanın _r önceki bölümlerinde gösterilen işleçler listesinde ve _t ham değişmez değerleri tanımlamak için kullanılabilir:

ReturnType operator "" _r(const char*);              // Raw literal operator
template<char...> ReturnType operator "" _t();       // Literal operator template

Derleyicinin normal davranışından farklı bir giriş dizisinin özel yorumunu sağlamak için ham değişmez değerleri kullanabilirsiniz. Örneğin, sırayı 4.75987 IEEE 754 kayan nokta türü yerine özel ondalık türüne dönüştüren bir değişmez değer tanımlayabilirsiniz. Pişmiş değişmez değerler gibi ham değişmez değerler de giriş dizilerinin derleme zamanı doğrulaması için kullanılabilir.

Örnek: Ham değişmez değerlerin sınırlamaları

Ham değişmez değer işleci ve değişmez değer işleci şablonu, aşağıdaki örnekte gösterildiği gibi yalnızca tam sayı ve kayan nokta kullanıcı tanımlı değişmez değerler için çalışır:

#include <cstddef>
#include <cstdio>

// Literal operator for user-defined INTEGRAL literal
void operator "" _dump(unsigned long long int lit)
{
    printf("operator \"\" _dump(unsigned long long int) : ===>%llu<===\n", lit);
};

// Literal operator for user-defined FLOATING literal
void operator "" _dump(long double lit)
{
    printf("operator \"\" _dump(long double)            : ===>%Lf<===\n",  lit);
};

// Literal operator for user-defined CHARACTER literal
void operator "" _dump(char lit)
{
    printf("operator \"\" _dump(char)                   : ===>%c<===\n",   lit);
};

void operator "" _dump(wchar_t lit)
{
    printf("operator \"\" _dump(wchar_t)                : ===>%d<===\n",   lit);
};

void operator "" _dump(char16_t lit)
{
    printf("operator \"\" _dump(char16_t)               : ===>%d<===\n",   lit);
};

void operator "" _dump(char32_t lit)
{
    printf("operator \"\" _dump(char32_t)               : ===>%d<===\n",   lit);
};

// Literal operator for user-defined STRING literal
void operator "" _dump(const     char* lit, size_t)
{
    printf("operator \"\" _dump(const     char*, size_t): ===>%s<===\n",   lit);
};

void operator "" _dump(const  wchar_t* lit, size_t)
{
    printf("operator \"\" _dump(const  wchar_t*, size_t): ===>%ls<===\n",  lit);
};

void operator "" _dump(const char16_t* lit, size_t)
{
    printf("operator \"\" _dump(const char16_t*, size_t):\n"                  );
};

void operator "" _dump(const char32_t* lit, size_t)
{
    printf("operator \"\" _dump(const char32_t*, size_t):\n"                  );
};

// Raw literal operator
void operator "" _dump_raw(const char* lit)
{
    printf("operator \"\" _dump_raw(const char*)        : ===>%s<===\n",   lit);
};

template<char...> void operator "" _dump_template();       // Literal operator template

int main(int argc, const char* argv[])
{
    42_dump;
    3.1415926_dump;
    3.14e+25_dump;
     'A'_dump;
    L'B'_dump;
    u'C'_dump;
    U'D'_dump;
      "Hello World"_dump;
     L"Wide String"_dump;
    u8"UTF-8 String"_dump;
     u"UTF-16 String"_dump;
     U"UTF-32 String"_dump;
    42_dump_raw;
    3.1415926_dump_raw;
    3.14e+25_dump_raw;

    // There is no raw literal operator or literal operator template support on these types:
    //  'A'_dump_raw;
    // L'B'_dump_raw;
    // u'C'_dump_raw;
    // U'D'_dump_raw;
    //   "Hello World"_dump_raw;
    //  L"Wide String"_dump_raw;
    // u8"UTF-8 String"_dump_raw;
    //  u"UTF-16 String"_dump_raw;
    //  U"UTF-32 String"_dump_raw;
}
operator "" _dump(unsigned long long int) : ===>42<===
operator "" _dump(long double)            : ===>3.141593<===
operator "" _dump(long double)            : ===>31399999999999998506827776.000000<===
operator "" _dump(char)                   : ===>A<===
operator "" _dump(wchar_t)                : ===>66<===
operator "" _dump(char16_t)               : ===>67<===
operator "" _dump(char32_t)               : ===>68<===
operator "" _dump(const     char*, size_t): ===>Hello World<===
operator "" _dump(const  wchar_t*, size_t): ===>Wide String<===
operator "" _dump(const     char*, size_t): ===>UTF-8 String<===
operator "" _dump(const char16_t*, size_t):
operator "" _dump(const char32_t*, size_t):
operator "" _dump_raw(const char*)        : ===>42<===
operator "" _dump_raw(const char*)        : ===>3.1415926<===
operator "" _dump_raw(const char*)        : ===>3.14e+25<===