C++ 17

Paylaş

C++ 11 ile birlikte Modern C++ olarak adlandırılan C++ diline C++ 17 ile eklenen yeni özelliklerle ilgili bilgiler örneklerle yer alıyor.

C++ 17 nedir?

C++ 17, C++ 11 ile birlikte Modern C++ olarak adlandırılan C++ diline yeni özelliklerin eklendiği bir sürümdür.

C veya C++ ile yazılım geliştirirken bazı işlemler sıklıkla tekrar edilir.

Dosya işlemlerinin yapıldığı bir uygulamada dosyanın var olup olmadığı, dosyanın açılıp açılmadığı gibi işlemler örnek olarak verilebilir.

Bu işlemleri sürekli yapmak yerine kendi fonksiyonlarımızı yazabilir veya hazır kütüphane kullanabiliriz.

Ancak belirli bir standardı olmayan kodlar büyük çaplı projelerde yazılımcılar arasında sorun olacaktır.

Dosya işlemleri için A yazılımcısı kendi fonksiyonunu, B yazılımcısı bir kütüphaneyi kullanabilir.

C++ bu ve bunun gibi işlemler için C++ 17 ile birlikte filesystem adında bir kütüphaneyi C++ standardına getirdi.

Benzer şekilde C++ birçok kütüphane ile kullanılan özellikleri C++ 17 ile birlikte standart haline getirdi.

C++ 17 ile gelen yeni özelliklere bakmadan önce C++ 14 yazıma bakmanızda fayda var.

Nasıl çalıştırılır?

C++ 17 ile gelen özellikler bir çok derleyici (GCC 6, Clang 4, MSVC 19.14) tarafından kullanıma hazır hale getirilmiştir.

C++ 17 özelliklerinin kullanmak için derleyici parametresine (flags) -std=c++1z veya -std=c++17 eklemek yeterli olacaktır.

1. Template argument deduction

C++ 17 ile birlikte artık Template sınıfları için veri türünü belirlemeden de kullanabilir hale geldi.

#include<iostream>
#include<vector>

using namespace std;

int main(){

    // C++ 17 öncesi
    vector<int> sayilar {5, 9, 77, 37, 133};

    cout << sayilar.size() << endl;

    // C++ 17
    vector sayilar1 {5, 9, 77, 37, 133};

    cout << sayilar1.size() << endl;

    return 0;
}

Bana göre bu özellik kod yazımını daha esnek hale getirse de kod okunurluğunu azaltmış gibi görünüyor.

2. auto

C++ 11 ile birlikte gelen auto anahtar kelimesinin kapsamı genişletildi.

#include<iostream>

using namespace std;

// C++ 17 öncesi
template <typename Type, Type value> void f() { cout << value << endl; }

// C++ 17
template <auto value> void f() { cout << value << endl; }

int main(){

    // C++ 17 Öncesi
    f<int, 10>();

    // C++ 17
    f<10>();

    return 0;
}

Bu özellikte kod okunurluğunu azalmakta ancak sınıf ve fonksiyon kullanımında oldukça faydalı görünüyor.

Ayrıca auto anahtar kelimesi uniform initialization ile kullanımında ortaya çıkan sorun ortadan kaldırıldı.

3. Folding expressions

C++ 11 ile birlikte gelen Variadic Template özelliği Template ile hazırlanmış sınıf veya fonksiyonlara sınırsız parametre aktarma özelliği kattı.

Variadic Template özelliğin kullanımı C++ 17 ile birlikte gelen folding expression ile daha esnek hale geldi.

#include<iostream>

using namespace std;

// C++ 17 öncesi
auto SumCpp11(){
    return 0;
}

template<typename T1, typename... T>
auto SumCpp11(T1 s, T... ts){
    return s + SumCpp11(ts...);
}

// C++ 17
template<typename ...Args>
auto sum(Args ...args) 
{ 
    return (args + ...); 
}

int main(){

    // C++ 17 Öncesi
    cout << SumCpp11(1, 2, 3, 4, 5) << endl;

    // C++ 17
    cout << sum(1, 2, 3, 4, 5) << endl;

    return 0;
}

4. constexpr

C++ 11 ile birlikte gelen C++ 14 ile özelliği genişleyen constexpr anahtar kelimesi temel olarak derleme zamanında işlem yapan bir terimdir.

C++ 17 ile birlikte constexpr anahtar kelimesinin kullanımı daha da genişletildi.

#include<iostream>

using namespace std;

// C++ 17 öncesi
template<int  N>
constexpr int fibonacciEski() {return fibonacciEski<N-1>() + fibonacciEski<N-2>(); }
template<>
constexpr int fibonacciEski<1>() { return 1; }
template<>
constexpr int fibonacciEski<0>() { return 0; }

// C++ 17
template<int N>
constexpr int fibonacci()
{
    if constexpr (N >= 2)
        return fibonacci<N-1>() + fibonacci<N-2>();
    else
        return N;
}

int main(){

    // constexpr lambda
    auto identity = [](int n) constexpr { return n; };
    cout << identity(123) << endl;

    // constexpr if
    cout << fibonacci<10>() << endl;

    return 0;
}

5. Lambda capture

C++ 11 ile birlikte gelen lambda fonksiyonları veya anonim fonksiyonlar temel olarak kod karmaşıklığını azalttı.

C++17 ile birlikte lambda kullanımı sırasında fonksiyon kapsamı dışındaki elemanlar erişim biçimi daha da genişletildi.

#include<iostream>

using namespace std;

struct MyObj {
  int value {123};
  auto getValueCopy() {
    return [*this] { return value; };
  }
  auto getValueRef() {
    return [this] { return value; };
  }
};

int main(){

    MyObj mo;
    auto valueCopy = mo.getValueCopy();
    auto valueRef = mo.getValueRef();
    mo.value = 321;
    cout << valueCopy() << endl;  // 123
    cout << valueRef() << endl;  // 321

    return 0;
}

C++ 17 ile birlikte artık lambda fonksiyonları *this anahtar kelimesini referans olarak parametre alıyor.

6. Inline variables

C++ 17 ile birlikte artık sınıf içinde inline değişken tanımlama imkanı getirildi.

#include<iostream>

using namespace std;

// C++ 17 öncesi
struct MyClass
{
    static const int sValue;
};

inline int const MyClass::sValue = 777;

// C++ 17
struct MyClass1
{
    inline static const int sValue = 777;
};

int main(){

    cout << MyClass::sValue << endl;

    cout << MyClass1::sValue << endl;

    return 0;
}

7. Nested Namespace

C++ 17 ile birlikte kod karmaşıklığını indiren bir diğer özellik olan ise nested namespace özelliğidir.

#include<iostream>

using namespace std;

// C++ 17 öncesi
namespace A {
  namespace B {
    namespace C {
      int i;
    }
  }
}

// C++ 17
namespace A::B::C {
  int j;
}

int main(){

    return 0;
}

8. Structured bindings

C++ 17 ile gelen güzel bir özellik ise structured bindings özelliğidir.

Özellik Dizi, Pair, Tuple gibi birden fazla değer içeren elemanlardaki verileri kolayca başka değişkenlere aktarmayı sağlıyor.

#include<iostream>
#include<tuple>

using namespace std;

int main(){

    tuple<int, string, string> bilgiler(1, "Yusuf", "Sezer");

    // C++ 17 öncesi
    int bid = get<0>(bilgiler);
    string badi = get<1>(bilgiler);
    string bsoyadi = get<2>(bilgiler);
    //tie(bid, badi, bsoyadi) = bilgiler;
    cout << bid << " " << badi << " " << bsoyadi << endl;

    // C++ 17
    auto [id, adi, soyadi] = bilgiler;
    cout << id << " " << adi << " " << soyadi << endl;

    return 0;
}

Bu özelliğin tie özelliğinden farkı değişkenlerin önceden oluşturulmasına ihtiyaç duymamasıdır.

9. init-statements if ve switch

C++ 17 ile birlikte if ve switch ifadelerinin kullanımı genişletildi.

#include<iostream>

using namespace std;

int kare(int x) { return x * x;};

int main(){

    // C++ 17 öncesi
    int sonuc = kare(3);

    if(sonuc == 9)
        cout << "Dogru";
    else
        cout << "Yanlis";

    // C++ 17
    if(int sonuc = kare(3); sonuc == 9)
        cout << "Dogru";
    else
        cout << "Yanlis";

    return 0;
}

Aslında gereksiz bir özellik gibi görünse de C++ STL gibi nesne döndüren sınıflarda kullanımı oldukça yararlıdır.

Ayrıca if ve switch içerisinde tanımlanan değişkenler if ve switch işlemi yapıldıktan sonra silineceğinden gereksiz bellek kullanımını azalacaktır.

10. UTF-8 Character Literals

C++ 11 ile birlikte gelen String Literals özelliğinde kullanılan ifadelerin kullanım alanı genişletildi.

#include<iostream>

using namespace std;

int main(){

    char a = u8'x';
    char b = u'x';
    char c = U'x';
    char d = L'x';

    cout << a << b << c << d << endl;

    return 0;
}

11. static_assert

C++ 11 ile birlikte gelen ve derleme zamanında değerleri test etmeye yarayan static_assert fonksiyonu artık mesaj yazmadan da kullanılabiliyor.

#include<iostream>
#include<cassert>

using namespace std;

int main(){

    // C++ 17 öncesi
    static_assert(sizeof(int) == 3, "Bir hata olustu.");

    // C++ 17
    static_assert(sizeof(int) == 3);

    return 0;
}

12. variant

Boost kütüphanesinde yer alan variant, optional, any özelliği C++17 ile dilin standardına eklendi.

#include<iostream>
#include<variant>

using namespace std;

int main(){

    variant<int, double> v{ 12 };
    get<int>(v); // == 12
    get<0>(v); // == 12
    v = 12.0;
    get<double>(v); // == 12.0
    get<1>(v); // == 12.0

    return 0;
}

optional özelliğinin kullanımı aşağıdaki gibidir.

#include<iostream>
#include<optional>

using namespace std;

optional<string> sonuc(bool x)
{
    return x ? std::optional("Doğru") : std::nullopt;
}

int main(){

    cout << sonuc(true).value() << endl;  // Doğru
    cout << sonuc(false).value_or("Yanlış") << endl;  // Yanlış
    //cout << sonuc(false).value() << endl;  // nullptr

    return 0;
}

13. Parallel algorithms ve execution policies

STL kütüphanesine paralel çalıştırabilme özelliği eklenmiştir.

#include<iostream>
#include<algorithm>
#include<execution> // std::execution::{par, par_unseq, seq} 

int main(){

    std::vector sayilar {5, 9, 77, 37, 133};

    std::sort(std::execution::par, sayilar.begin(), sayilar.end());

    for (auto &&sayi : sayilar){
      std::cout << sayi << " ";
    }

    std::cout << std::endl;

    return 0;
}

Özellik STL kütüphanesinde yer alan bir çok metot ile kullanılabilmektedir.

C++ STL hakkın detaylı bilgi almak için C++ STL yazıma bakmalısın.

14. File system library

Boost kütüphanesinde yer alan  boost.filesystem özelliği std::filesystem kütüphanesi olarak C++17 ile dilin standardına eklendi.

Özelliği ait metotlar ve kullanımı aşağıdaki örnekte yer almaktadır.

#include<iostream>
#include<filesystem>

namespace fs = std::filesystem;

int main(){

    fs::path my_path = fs::current_path();
    std::cout << "current_path: " << my_path << std::endl;
    std::cout << "filename(): " << my_path.filename() << std::endl;
    std::cout << "extension(): " << my_path.extension() << std::endl;
    std::cout << "string(): " << my_path.string() << std::endl;
    std::cout << "root_directory(): " << my_path.root_directory() << std::endl;
    std::cout << "root_name(): " << my_path.root_name() << std::endl;
    std::cout << "root_path(): " << my_path.root_path() << std::endl;
    std::cout << "parent_path(): " << my_path.parent_path() << std::endl;
    std::cout << "stem(): " << my_path.stem() << std::endl;
    std::cout << std::endl;
    std::cout.setf(std::cout.boolalpha);
    std::cout << "empty(): " << my_path.empty() << std::endl;
    std::cout << "has_filename(): " << my_path.has_filename() << std::endl;
    std::cout << "has_extension(): " << my_path.has_extension() << std::endl;
    std::cout << "has_parent_path(): " << my_path.has_parent_path() << std::endl;
    std::cout << "has_relative_path(): " << my_path.has_relative_path() << std::endl;
    std::cout << "has_root_directory(): " << my_path.has_root_directory() << std::endl;
    std::cout << "has_root_name(): " << my_path.has_root_name() << std::endl;
    std::cout << "has_root_path(): " << my_path.has_root_path() << std::endl;
    std::cout << "has_stem(): " << my_path.has_stem() << std::endl;
    std::cout << "is_absolute(): " << my_path.is_absolute() << std::endl;
    std::cout << "is_relative(): " << my_path.is_relative() << std::endl;
    std::cout << "preferred_separator: " << fs::path::preferred_separator << std::endl;

    for (auto &&path : my_path) {
        std::cout << path << ", ";
    }

    std::cout << "\n\n";

    std::cout.setf(std::cout.boolalpha);
    std::cout << "fs::exists(): " << fs::exists(my_path) << std::endl;
    std::cout << "fs::create_directories(): " << fs::create_directories("new_directory") << std::endl;
    std::cout << "fs::create_directory(): " << fs::create_directory("new_directory") << std::endl;

    fs::current_path(fs::temp_directory_path());
    fs::create_directories("sandbox/1/2/a");
    fs::create_directory("sandbox/1/2/b");
    fs::permissions("sandbox/1/2/b", fs::perms::others_all, fs::perm_options::remove);
    fs::create_directory("sandbox/1/2/c", "sandbox/1/2/b");
    std::system("ls -l sandbox/1/2");
    std::system("tree sandbox");
    fs::remove_all("sandbox");

    for (auto &&dir_entry : fs::recursive_directory_iterator{my_path}) {
        fs::file_status status = dir_entry.status();
        fs::file_type type = status.type();
        fs::perms permission = status.permissions();
        std::cout.setf(std::cout.boolalpha);
        std::cout << dir_entry << "\n";
        std::cout << "is_block_file(): " << dir_entry.is_block_file() << "\n";
        std::cout << "is_character_file(): " << dir_entry.is_character_file() << "\n";
        std::cout << "is_directory(): " << dir_entry.is_directory() << "\n";
        std::cout << "fs::is_directory(): " << fs::is_directory(status) << "\n";
        std::cout << "fs::is_empty(): " << fs::is_empty(dir_entry) << "\n";
        std::cout << "is_fifo(): " << dir_entry.is_fifo() << "\n";
        std::cout << "is_other(): " << dir_entry.is_other() << "\n";
        std::cout << "is_regular_file(): " << dir_entry.is_regular_file() << "\n";
        std::cout << "is_socket(): " << dir_entry.is_socket() << "\n";
        std::cout << "is_symlink(): " << dir_entry.is_symlink() << "\n\n";
    }

    return 0;
}

Özellik ile birlikte dosya ve dizin işlemleri standart olarak daha kolay ve anlaşılır hale gelmiş oldu.

15. String View

Metinsel ifadeler, dizi karakterleri veya string işlemlerini daha hızlı ve daha az bellek kullanımını sağlayan std::string_view özelliği eklenmiştir.

#include<iostream>
#include<string_view>

void print(std::string_view sv) {
    std::cout << sv << "\n";
    std::cout << "Uzunluk: " << sv.length() << "\n";
}

int main(){
    std::string str = "Merhaba, Dünya!";
    std::string_view sv(str); // std::string'i std::string_view'e dönüştürme

    print(sv);

    // std::string'i doğrudan std::string_view'e dönüştürme
    print("Hello, World!");

    return 0;
}

Özellik string ile kullanılan bir çok metodu kullanmayı sağlar.

String view ayrıca bellek ihtiyacı olmadan işlemler yapmayı sağlayarak performans artışı sağlar.

16. Diğer

C++ 17 temel olarak C++ 11 ve C++ 14 ile gelen özelliklerde bulunan hataları düzeltmiş ve bazı özelliklerin daha esnek kullanımını sağlamıştır.

C++ 17 ile birlikte Boost gibi C++ kütüphanelerinde yer alan çeşitli özellikleri standart haline getirmiştir.

C++ Modern C++ ile birlikte artık Modern programlama dillerinden yer alan birçok özelliği dilin standardı olarak belirlemiştir.

Yeni güncellemeler ve dil hakkında detaylı bilgi için isocpp.org adresine bakabilirsiniz.

Hayırlı günler dilerim.


Bunlarda ilgini çekebilir


LinkedIn grubuna buradan katılın.