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.

Hiç yorum yok:

Yorum Gönder