constexpr etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
constexpr etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

9 Nisan 2019 Salı

constexpr Döndüren Metod

1. constexpr metod Sonucu Derleme Zamanında Hesaplanmak Zorunda Değildir
constexpr bir konuda yanlış anlaşılıyor. constexpr değeri derleme zamanında hesaplanmak zorunda değil! Yani şu varsayım yanlış.
A constexpr function is computed during compile time and not during execution, as long as the value being passed to it as a parameter is a constant.
Açıklaması şöyle
the compiler can do so at its discretion, just as with a "pure" function that isn't constexpr. Unless you use it in a context where a compile-time constant is required, such as initialization of a constexpr variable, or use in an array bound (beware VLA g++ extension, though) or as a non-type template argument. For these cases, compile-time evaluation is required. (This is not an exhaustive list: there are other contexts which require compile time constants such as switch case labels, but how do you send a case label value to cout?)
Eğer constexpr metodun çağrıldığı bağlam (context) constexpr değilse zaten yapacak bir şey yok. Eğer constexpr ise bile derleyici bunu yapmak zorunda değil. Ancak yapacağını varsayıyoruz :)

Örnek - Derlemek İçin memoization
Elimizde şöyle bir kod olsun. constexpr ise derlemesi 3 saniye sürüyor ancak değilse derlemesi çok daha uzun sürüyor.
constexpr long long fibonacci(int num) {
  if (num <= 2) return 1;
  return fibonacci(num - 1) + fibonacci(num - 2);
}

auto num = fibonacci(70);
Açıklaması şöyle
constexpr functions have no side-effects and can thus be memoized without worry. Given the disparity in runtime the simplest explanation is that the compiler memoizes constexpr functions during compile-time. This means that fibonacci(n) is only computed once for each n, and all other recursive calls get returned from a lookup table.
Örnek - Sol Tarafın constexpr Olması veya Olmaması
Açıklaması şöyle.
The constexpr keyword says that the function must be evaluated at compile time, if it's called in a constexpr context
Aradaki farkı görmek için şöyle yaparız.
constexpr int sum(int n)
{    
  return (n <= 0) ? 0 : n + sum(n-1);
}

int main()
{
  int i;
  std::cin >> i;

  constexpr int s1 = sum(4); // OK, evaluated at compile time
  int s2 = sum(i);           // OK, evaluated at run time
  constexpr int s3 = sum(i); // Error, i cannot be evaluated at compile time
  int s4 = sum(4);           // OK, execution time depends on the compiler's mood
}
Örnek
Aşağıdaki kod derlenmez. Burada sol taraf constexpr dolayısıyla f() metodunun çağırdığı her alt metod da constexpr olmalı
void increment (int& v)
{
  ++v;
}

int constexpr f()
{
  int v = 0;
  increment (v);
  return v;
}

int main()
{
  cout << f() << '\n';
}
Hata olarak şunu alırız 
constexpr function 'f' cannot result in a constant expression.
Örnek

Aşağıdaki örnek'te -O0 ile derlenince vakit alacak şekilde çalışıyor.
#include <iostream>
#include <chrono>

constexpr long long addition(long long num)
{
  long long sum = 0;
  for (int i = 0; i <= num; i++)
  {
    sum += i;
  }

  return sum;
}

int main()
{
  std::cout << addition(500000000);  //500 mill //executes in 1.957 seconds
}
2. Header İçinde constexpr Metod Tanımlama
Burada dikkat edilmesi gereken nokta constexpr metodlar inline edilirler.
(§7.1.5/2): "constexpr functions and constexpr constructors are implicitly inline (7.1.2)."
Dolayısıyla bir header dosyası içinde tanımlamak en iyisi.

3. C++11 ve C++14 Arasındaki İmzaı Farkı
metod sonucundaki constexpr kullanımı C++11 ile geldi. Ancak C++14 ile değişiklik yapıldı. C++11 ile metod const kabul edilirken, C++14'ten metod const kabul edilmiyor. Yani sınıf içindeki değişkenlere yeni değer atanabilir. Fark şöyle
struct A { constexpr int func (); };

// struct A { constexpr int func () const; }; <-- C++11
// struct A { constexpr int func ();       }; <-- C++14
4. constexpr Function İçinde Yerel Değişkenleri Değiştirme
constexpr dönen bir metod içindeki yerel değişkenler değiştirileblir. 
Örnek
Şöyle yaparız.
constexpr auto i_can() {
  int a = 8;
  a = 9;
  //...
}
Örnek
Şöyle yaparız
constexpr auto demo()
{
  int arr[10] = {};
  arr[5] = 9;
  return arr[5];
}
Eğer bir nesne kullanmak istersek nesnenin metodunun da constexpr olması gerekir.

4 Şubat 2019 Pazartesi

constexpr

Metodu Sonucu Tanımlama
constexpr Döndüren Metod yazısına taşıdım.

const Alan vs constexpr Alan
constexpr Alan derleme zamanı değer alır ve bir daha değiştirilemez. Ancak const alan runtime'da değer alır ve arık bundan sonra değiştirilemz. Bu yüzden bazı template metodlar const değişken ile derlenemezler. Şu kod derlenmez
const size_t n = 3;
Eigen::Matrix<double, n, n> A;
Şöyle yaparız
constexpr size_t n = 3;
Eigen::Matrix<double, n, n> A;
Eigen::Matrix<double, n, n> B;
1. Alan Tanımlama
Şöyle yaparız.
constexpr const char foo[] = "blee";
Şöyle yaparız.
constexpr double some_double = 1.0;
1.1 Alan Tanımla - String Literal
Şu kod uyarı verir. Çünkü constexpr char* sadece  constant pointer to a non-const char anlamına gelir.
// warning: ISO C++ forbids converting a string constant to ‘char*’    
static constexpr char* name_ = "A";       
Şöyle yaparız. Bu kod constant pointer to a constant char anlamına gelir.
static constexpr const char* name_ = "A";    
2. Static Alan Tanımlama
Şöyle yaparız.
constexpr static int x{20};
Eğer istenirse static bir alana referans bile alınabilir. Şöyle yaparız.
constexpr static int x{20};
constexpr const int& z = x;
3. Static Üye Tanımlama
C++17 ile şöyle yaparız.
class Foo
{
  public:
    constexpr static std::tuple<int, unsigned int, unsigned short> table[3]
    = {std::make_tuple(1, 2, 3),
        std::make_tuple(4, 5, 6),
        std::make_tuple(7, 8, 9)};
};
C++11 derleyicisinde şu satırı eklemek te gerekir.
constexpr std::tuple<int, unsigned int, unsigned short> Table_class::table[3];
En Eski Yöntem
Eski C++ ile integral olmayan static const değişkenleri sınıfın özelliği gibi tanımlamak mümkün değildi. Bu yüzden aşağıdaki gibi yapmak gerekiyordu.
//my_class.hpp
private:
static const double some_double;

//my_class.cpp
const double my_class::some_double = 1.0;

Diğer Notlar
1. Trivial Destructor'a Sahip Olmayan Şeyler constexpr Olamaz
Örnek'teki kod derlenmez!
constexpr const std::string foo = "blee";
2. constexpr'nin Sağ Tarafı da constexpr olabilir.
Bazı basit örnekler şöyle
static constexpr int arr[] = {1,2,3,4,5,6};
constexpr const int *first = arr;
constexpr const int *second = first + 1; // would fail if first wasn't constexpr
constexpr int i = *second;
Eğer constexpr'nin sağ tarafında kullanılan değişken de constexpr değilse derleme hatası alırız.
struct S {
    constexpr int f() const { return 1; }  
};

int main() {
    static constexpr S s{};
    const S *sp = &s;
    constexpr int i = sp->f(); // error: sp not a constant expression
}

4. if constexpr
if constexpr yazısına taşıdım.