Bagikan melalui


Literal yang ditentukan pengguna

Ada enam kategori literal utama dalam C++: bilangan bulat, karakter, floating-point, string, boolean, dan pointer. Mulai dari C++11, Anda dapat menentukan literal Anda sendiri berdasarkan kategori ini, untuk menyediakan pintasan sintaktik untuk idiom umum dan meningkatkan keamanan jenis. Misalnya, Anda memiliki Distance kelas. Anda dapat menentukan harfiah untuk kilometer dan satu lagi untuk mil, dan mendorong pengguna untuk eksplisit tentang unit pengukuran dengan menulis: auto d = 42.0_km atau auto d = 42.0_mi. Tidak ada keunggulan performa atau kerugian bagi literal yang ditentukan pengguna; mereka terutama untuk kenyamanan atau untuk pengurangan jenis waktu kompilasi. Pustaka Standar memiliki literal yang ditentukan pengguna untuk std::string, untuk std::complex, dan untuk unit dalam operasi waktu dan durasi di <header chrono> :

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

Tanda tangan operator harfiah yang ditentukan pengguna

Anda menerapkan literal yang ditentukan pengguna dengan mendefinisikan operator"" pada cakupan namespace dengan salah satu formulir berikut:

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

Nama operator dalam contoh sebelumnya adalah tempat penampung untuk nama apa pun yang Anda berikan; namun, garis bawah terkemuka diperlukan. (Hanya Pustaka Standar yang diizinkan untuk menentukan harfiah tanpa garis bawah.) Jenis pengembalian adalah tempat Anda menyesuaikan konversi atau operasi lain yang dilakukan oleh literal. Selain itu, salah satu operator ini dapat didefinisikan sebagai constexpr.

Literal yang dimasak

Dalam kode sumber, harfiah apa pun, baik yang ditentukan pengguna atau tidak, pada dasarnya adalah urutan karakter alfanumerik, seperti 101, atau 54.7, atau "hello"true. Pengkompilasi menafsirkan urutan sebagai bilangan bulat, float, string const char*, dan sebagainya. Literal yang ditentukan pengguna yang menerima sebagai input apa pun jenis pengkompilasi yang ditetapkan ke nilai harfiah secara informal dikenal sebagai harfiah yang dimasak. Semua operator di atas kecuali _r dan _t dimasak harfiah. Misalnya, harfiah 42.0_km akan mengikat operator bernama _km yang memiliki tanda tangan yang mirip dengan _b dan harfiah 42_km akan mengikat operator dengan tanda tangan yang mirip dengan _a.

Contoh berikut menunjukkan bagaimana literal yang ditentukan pengguna dapat mendorong penelepon untuk eksplisit tentang input mereka. Untuk membuat Distance, pengguna harus secara eksplisit menentukan kilometer atau mil dengan menggunakan literal yang ditentukan pengguna yang sesuai. Anda dapat mencapai hasil yang sama dengan cara lain, tetapi literal yang ditentukan pengguna kurang verbose daripada alternatif.

// 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;
}

Angka harfiah harus menggunakan desimal. Jika tidak, angka akan ditafsirkan sebagai bilangan bulat, dan jenisnya tidak akan kompatibel dengan operator. Untuk input titik mengambang, jenisnya harus long double, dan untuk jenis integral harus long long.

Literal mentah

Dalam literal yang ditentukan pengguna mentah, operator yang Anda tentukan menerima harfiah sebagai urutan nilai karakter. Terserah Anda untuk menafsirkan urutan tersebut sebagai angka atau string atau jenis lainnya. Dalam daftar operator yang ditampilkan sebelumnya di halaman ini, _r dan _t dapat digunakan untuk menentukan literal mentah:

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

Anda dapat menggunakan literal mentah untuk memberikan interpretasi kustom dari urutan input yang berbeda dari perilaku normal kompilator. Misalnya, Anda dapat menentukan literal yang mengonversi urutan 4.75987 menjadi jenis Desimal kustom alih-alih jenis titik mengambang IEEE 754. Literal mentah, seperti literal yang dimasak, juga dapat digunakan untuk validasi urutan input waktu kompilasi.

Contoh: Batasan literal mentah

Operator literal mentah dan templat operator harfiah hanya berfungsi untuk literal integral dan floating-point yang ditentukan pengguna, seperti yang ditunjukkan oleh contoh berikut:

#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<===