18 Şubat 2020 Salı

C++20 concept

Giriş
Şu satırı dahil ederiz.
#include <concepts>
Açıklaması şöyle.
A Concept is basically a template parameter with constraints, e.g.
C++20 ile geliyor. Eski kodlarda derleme esnasında hataları yakalamak için std::enable_if kullanırız. Yani şöyle yaparız. Yeni kodlarda concept kullanılır
template<typename T,
         std::enable_if_t<has_less_than_op<T>::value, int> = 0>
const T& comp(const T& a , const T& b) 
{return a<b?a:b;}
Concept Scope
Concept sınıf içinde tanımlanamaz. Şu kod derlenmez. Hata olarak şunu alırız. "error: concept declarations may only appear in global or namespace scope"
struct A
{
  template <typename T>
  concept foo = true;
};
Concept Tanımlama
Söz dizimi şöyle. Concept isminden sonra contraint ifadesi gelir.
concept-definition:
  concept concept-name = constraint-expression ;
concept-name:
  identifier
Constraint ifadesi iki şekilde tanımlanabilir.

1. concept X = std::type trait şeklinde tanımlanır. Type trait olarak std isim alanında milyon tane metod var.

Örnek
Şöyle yaparız
template<typename T>
concept MyClassIter = std::is_same_v<
                        MyClass, 
                        typename std::iterator_traits<T>::value_type
                      >;
2. concept X = requires{...} şeklinde tanımlanır.
Concept sadece generic kodda foo() requires X şeklinde kullanılır.
Örnek - generic olan ve olmayan kod
Generic olmayan kod derleme hatası verir. Görmek için şöyle yaparız
void f1(int a) requires true;               // error: non-templated function

template<typename T>
  auto f2(T a) -> bool requires true;       // OK
Örnek
Şöyle yaparız
#include <iostream>
#include <vector>

template <typename T>
concept has_begin = requires(T t) {t.begin();};

int main(int argc, char *argv[])
{
  std::cout << has_begin<std::vector<int>> << std::endl;
}
Concept Kullanarak std::enable_if'ten Kurtulmak
Örneklerin çoğunu C++20 concept Kullanarak std::enable_if'ten Kurtulmak yazısına taşıdım.

Örnek
concept tanımı static_assert ile birlikte kullanılabilir. Elimizde şöyle bir kod olsun.
template<class T>
concept Valid = requires(T t) {
    { t.x };
};

struct ValidExample   { int x; };
struct InValidExample {};
Şöyle yaparız.
static_assert(Valid<ValidExample>); // ValidExample is Valid
static_assert(!Valid<InValidExample>); // InValidExample is not Valid
Örnek
constraint'i concept olmadan kullanmak hatalı olabilir. Şu kod hatalı.
template <typename T> inline constexpr bool C1 = true;    
template <typename T> inline constexpr bool C2 = true;

template <typename T> requires C1<T> && C2<T> 
constexpr int foo() { return 0; }

template <typename T> requires C1<T> 
constexpr int foo() { return 1; }

constexpr int bar() {
    return foo<int>();
}

Hiç yorum yok:

Yorum Gönder