26 Nisan 2019 Cuma

std::clamp

Giriş
C++17 ile geliyor.

Metodun içi şöyle. return ile assert beraber kullanılıyor.
template<class T, class Compare>
constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp )
{
    return assert( !comp(hi, lo) ),
        comp(v, lo) ? lo : comp(hi, v) ? hi : v;
}
Örnek
Şöyle yaparız.
if (v == std::clamp(v, lo, hi)) {
    // lo <= v && v <= hi.
}


std::function ve Lambda

Constructor
std::function lambda kullanılarak kurulabilir.

Örnek
Şöyle yaparız. std::function const int& almasına rağmen lambda'ya int geçebildiği için sorun olmaz.
Yani std::function'a geçilen parametre tipleri lambda'ya da geçilebildiği müddetçe kod derlenir.
std::function<void(const int&)> f = [](int a)
{

};
std::function Parametre Tipi Yerine Lambda Geçmek
std::function lambda ile ilklendirilebilir ancak şunu unutmamak gerekir, lambda nesnesi std::function değildir! Dolayısıyla reference olarak (const & değil!) std::function parametresi bekleyen metodlara lambda geçilirse hata alınabilir.

Mutable Lambda
Mutable Lambda yazısına taşıdım.

Closure - Capture By Value

1. İsim Vermeden Capture
Closure içinde kullanılan değişkenlerin kopyasını aldığı için kullanması kolaydır.

Örnek
Elimizde şöyle bir closure olsun.
[=] { return x + 1; } // capture by value
Derleyici şöyle bir kod üretir.
class bar {
  int x;
public:
  bar(int x) : x(x) {}
  int operator()() const { return x + 1; }
};
1.1 Const Değişkenler İçin İsim Vermeden Capture

Örnek
Şöyle yaparız.
int main(){
  const int x = 123;
  auto g = []() { std::cout << x << "\n"; };
  g();
}
const float değişkenler bir sebepten dolayı bu kuralın dışında bırakılmış. Şu kod derlenmez.
int main(){
  const float x = 123;
  auto g = []() { std::cout << x << "\n"; };
  g();
}

2. İsim İle Capture
İsim vererek closure yapınca hangi değişkenlerin kopyasının alındığını görmek daha kolay.

Örnek
Şöyle yaparız. Sadece s değişkenine erişileceği belirtilir.
std::string s{"Test"};
auto T = [s]() { std::cout << s.size() << ' '; };  // make a copy of s
Örnek
İsim vererek closure yapınca aynı zamanda nesneyi move etmek için şöyle yaparız.
std::vector<int> vector;
auto lambda = [vec = std::move(vector)]() { /* the lambda owns the vector now */ });
3. Init Capture
Şöyle yaparız. i değişkeni yaratılır ve value olarak ilklendirilir.
auto inc = [i=0]() mutable { return i++; };
Açıklaması şöyle
The mutable is required because lambdas are const by default, and we need to directly modify the member i.
4. Mutable Closure
Capture By Value kullansak bile capture edilen tüm value değişkenler const kabul edilir. Eğer değişkenin değeri ile oynamak istersek Closure mutable olarak işaretlenmelidir.

Örnek
Şöyle yaparız.
int x = 3;
auto f1 = [x]() mutable
{
  return x++;
};
Örnek
mutable ve const Closure'lar birbirlerini kullanmaz. Şu kod derlenmez.
int x = 3;
auto f1 = [x]() mutable
{
    return x++;
};
auto f2 = [f1]()
{
    return f1();
};

25 Nisan 2019 Perşembe

constructible traits

std::is_constructible
İmzası şöyle. Variadic'tir. is_copy_constructible ve is_move_constructible ise variadic değildir.
template <class T, class... Args> struct is_constructible;
Verilen parametreleri kullanarak sınıfın kurulup kurulamayacağını döner. Yani şu kodu yazıp yazamayacağımızı döner.
T obj();
Örnek - T tipi tam tanımlı olmalı
Elimizde şöyle bir kod olsun.
#include <iostream>

class A;

int main()
{
  std::cout << std::is_constructible<A>::value << std::endl;
}
Bu kod tanımsız davranışa sebep olur. Açıklaması şöyle.
T and all types in the template parameter pack Args shall be complete typescv void, or arrays of unknown bound.
Örnek - Destructor erişilebilir olmalı
Destructor private olduğu için is_constructible false döner
#include <type_traits>

class Foo
{
public:
  Foo() {}
private:
  // Destructor is private!
  ~Foo(){}
};

int main()
{

  if(!std::is_constructible<Foo>::value)
  {
    std::cout << "is_constructible failed" << std::endl;
  }
}
std::is_default_constructible
Açıklaması şöyle.
T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound. Otherwise, the behavior is undefined.
Bu  metod aslında altta
T obj();
tipi için std::is_constructible çağrısını kullanıyor.

Şöyle yaparız.
struct X { };  // OK
static_assert(std::is_default_constructible<X>::value, "Error"); 
Eğer T tipi tam değilse false döner. Örneğin aynı kodu X yapısı içine taşıyalım. Şöyle yaparız.
struct X {
 static_assert(std::is_default_constructible<X>::value, "Error");  // Fails
};
std::is_move_constructible
move constructible traits yazısına taşıdım.

std::is_nothrow_constructible
Verilen parametreleri kullanarak sınıfın kurulup kurulamayacağını döner. Variadic'tir. is_copy_constructible ve is_move_constructible ise variadic değildir.

Örnek ver

std::is_trivially_constructible
Verilen parametreleri kullanarak sınıfın kurulup kurulamayacağını döner. Variadic'tir. is_copy_constructible ve is_move_constructible ise variadic değildir.

Örnek ver