SORU
22 EKİM 2014, ÇARŞAMBA


void_t "kavramlarını uygulama"?

Hangi sırasında onun Roman kullanır tartıştı Walter Brown's CppCon2014 talk on template metaprogramming, ikinci bölümü izliyordum void_t<> inşaat. Biri sırasında sorulan oldukça anlamadığım bir soru. (doğrudan bağlantı kodu daha önce doğrudan gerçekleşti soru) gider

Biri ona sordu: "bu kavramlar şu anda uygulayabilir miyiz?" diye cevap verdi "Evet, yaptım ... sözdizimi biraz farklıdır".

Bu değişim Kavramları Lite hakkında olacağını anladım. Bu model gerçektenbuçok yönlü? Sebebi ne olursa olsun, bunu görüyorum. Bu görünebilir gibi birini (veya çizim) nasıl bir şey açıklayabilir miyim? Sadece enable_if ve sorgulayıcı atıfta ne belirleyici özellikleri, ya bu?

void_t şablon aşağıdaki gibi tanımlanır

template<class ...> using void_t = void;

Bu tür ifadeler, iyi biçimlendirilmiş olup olmadığını tespit etmek için, bu is_copy_assignable type özelliği uygulamak için kullanır:

//helper type
template<class T>
using copy_assignment_t
= decltype(declval<T&>() = declval<T const&>());

//base case template
template<class T, class=void>
struct is_copy_assignable : std::false_type {};

//SFINAE version only for types where copy_assignment_t<T> is well-formed.
template<class T>
struct is_copy_assignable<T, void_t<copy_assignment_t<T>>> 
: std::is_same<copy_assignment_t<T>,T&> {};

Bu konuşma nedeniyle, bu örnek, nasıl çalıştığını anlıyorum, ama Kavram gibi bir şey buradan Lite gördüğüm kadarıyla yok.

Edit: Kod yazım hatası.

CEVAP
23 EKİM 2014, PERŞEMBE


Evet, kavramlar temelde elbiseler up lite SFİNAE. Artı derin içgözlem daha aşırı yükleme için izin verir. Ancak bu sadece konsept concept bool olarak tanımlanan koşullarına çalışır. Gelişmiş aşırı akım kavramı doğrulamaları ile çalışmaz, ama koşullu aşırı kullanılabilir. Koşullar tanımlamak, şablonlar sınırlamak için nasıl gösterir, ve C 14 aşırı yük fonksiyonları. Bu biraz uzun ama araçları C 14 bunu yapmak için gerekli tüm oluşturma üzerinde gider.

Koşullarına Tanımlama

İlk olarak, tür std::declval decltype bütün her yerde yüklem okumak için çirkin. Bunun yerine, bir işlevi izleyen bir decltype(Eric Niebler blog yazısı here) kullanarak, bu gibi sınırlamak aslında biz yararlanabiliriz:

struct Incrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(  x);
};

Eğer öyleyse x geçerli değilse, o zaman requires_ üye işlevi çağrılabilir. Eğer requires_ çağrı void_t kullanıyorsa sadece kontrol eden models bir özellik oluşturmak, böylece:

template<class Concept, class Enable=void>
struct models
: std::false_type
{};

template<class Concept, class... Ts>
struct models<Concept(Ts...), void_t< 
    decltype(std::declval<Concept>().requires_(std::declval<Ts>()...))
>>
: std::true_type
{};

Kısıtlayıcı Şablonları

Şablon kavramına dayalı sınırlamak istiyoruz, hala enable_if kullanmak gerekir ama bu makro daha temiz yapmak yardımcı olmak için kullanabilirsiniz, böylece:

#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__), int>::type = 0

Incrementable kavramına dayalı kısıtlı olduğunu increment bir fonksiyon tanımlayabiliriz:

template<class T, REQUIRES(models<Incrementable(T)>())>
void increment(T& x)
{
      x;
}

Eğer increment ararsak bir şey ile böyle bir hata alacağız Incrementable değil yani:

test.cpp:23:5: error: no matching function for call to 'incrementable'
    incrementable(f);
    ^~~~~~~~~~~~~
test.cpp:11:19: note: candidate template ignored: disabled by 'enable_if' [with T = foo]
template<class T, REQUIRES(models<Incrementable(T)>())>
                  ^

Aşırı Yükleme İşlevleri

Şimdi ise aşırı yükleme yapmak istiyorsak, koşullu aşırı kullanmak istiyoruz. std::advance kullanarak bir konsept yaratmak istiyoruz ki, koşullar, bu(şimdilik decrementable durum göz ardı edeceğiz) gibi tanımlayabiliriz:

struct Incrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(  x);
};

struct Advanceable
{
    template<class T, class I>
    auto requires_(T&& x, I&& i) -> decltype(x  = i);
};

template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
void advance(Iterator& it, int n)
{
    it  = n;
}

template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
void advance(Iterator& it, int n)
{
    while (n--)   it;
}

Ancak, bu nedenler bir belirsiz bir yükleme(kavramlar lite bu hala belirsiz aşırı olmadığı sürece biz değiştirmek bizim koşullarına başvurmak için diğer koşullar bir concept bool) olduğunda kullanılan std::vector yineleyici. Yapmak istediğimiz şey, koşullu aşırı kullanarak yapabiliriz hangi aramalar düzen vardır. Böyle bir şey geçerli değildir C) yazma düşünülebilir:

template<class Iterator>
void advance(Iterator& it, int n) if (models<Advanceable(Iterator, int)>())
{
    it  = n;
} 
else if (models<Incrementable(Iterator)>())
{
    while (n--)   it;
}

Eğer ilk fonksiyonu değil ise, bir sonraki işlevini çağırır. Bu yüzden iki fonksiyon için uygulayarak başlayalım. Parametre olarak şablon: iki işlevi nesneleri kabul eden bir sınıfı basic_conditional adlı yaratacağız

struct Callable
{
    template<class F, class... Ts>
    auto requires_(F&& f, Ts&&... xs) -> decltype(
        f(std::forward<Ts>(xs)...)
    );
};

template<class F1, class F2>
struct basic_conditional
{
    // We don't need to use a requires clause here because the trailing
    // `decltype` will constrain the template for us.
    template<class... Ts>
    auto operator()(Ts&&... xs) -> decltype(F1()(std::forward<Ts>(xs)...))
    {
        return F1()(std::forward<Ts>(xs)...);
    }
    // Here we add a requires clause to make this function callable only if
    // `F1` is not callable.
    template<class... Ts, REQUIRES(!models<Callable(F1, Ts&&...)>())>
    auto operator()(Ts&&... xs) -> decltype(F2()(std::forward<Ts>(xs)...))
    {
        return F2()(std::forward<Ts>(xs)...);
    }
};

Şimdi bu işlevleri yerine nesneler gibi fonksiyonları tanımlamamız gerekiyor

struct advance_advanceable
{
    template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
    void operator()(Iterator& it, int n) const
    {
        it  = n;
    }
};

struct advance_incrementable
{
    template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
    void operator()(Iterator& it, int n) const
    {
        while (n--)   it;
    }
};

static conditional<advance_advanceable, advance_incrementable> advance = {};

Eğer std::vector ile kullanmaya çalışırsak şimdi:

std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
auto iterator = v.begin();
advance(iterator, 4);
std::cout << *iterator << std::endl;

Derleme ve 5 baskı.

Ancak, std::advance aslında üç aşırı vardır, bu yüzden basic_conditional fonksiyonlar özyineleme kullanarak herhangi bir sayı için çalışan conditional uygulamak için kullanabiliriz:

template<class F, class... Fs>
struct conditional : basic_conditional<F, conditional<Fs...>>
{};

template<class F>
struct conditional<F> : F
{};

Yani, şimdi bu gibi std::advance tam yazabiliriz:

struct Incrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(  x);
};

struct Decrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(--x);
};

struct Advanceable
{
    template<class T, class I>
    auto requires_(T&& x, I&& i) -> decltype(x  = i);
};

struct advance_advanceable
{
    template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
    void operator()(Iterator& it, int n) const
    {
        it  = n;
    }
};

struct advance_decrementable
{
    template<class Iterator, REQUIRES(models<Decrementable(Iterator)>())>
    void operator()(Iterator& it, int n) const
    {
        if (n > 0) while (n--)   it;
        else 
        {
            n *= -1;
            while (n--) --it;
        }
    }
};

struct advance_incrementable
{
    template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
    void operator()(Iterator& it, int n) const
    {
        while (n--)   it;
    }
};

static conditional<advance_advanceable, advance_decrementable, advance_incrementable> advance = {};

Lambda İle Aşırı Yükleme

Ancak, ayrıca, Lambda temiz yazmak için yardımcı olabilecek işlevi nesneleri yerine bunu yazmak için kullanabiliriz. Derleme zamanında Lambda oluşturmak için STATIC_LAMBDA bu makroyu kullanın:

struct wrapper_factor
{
    template<class F>
    constexpr wrapper<F> operator  = (F*)
    {
        return {};
    }
};

struct addr_add
{
    template<class T>
    friend typename std::remove_reference<T>::type *operator (addr_add, T &&t) 
    {
        return &t;
    }
};

#define STATIC_LAMBDA wrapper_factor()  = true ? nullptr : addr_add()   []

Ve constexpr make_conditional bir işlev eklemek:

template<class... Fs>
constexpr conditional<Fs...> make_conditional(Fs...)
{
    return {};
}

O zaman şimdi böyle advance fonksiyon yazabiliriz:

constexpr const advance = make_conditional(
    STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Advanceable(decltype(it), int)>()))
    {
        it  = n;
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Decrementable(decltype(it))>()))
    {
        if (n > 0) while (n--)   it;
        else 
        {
            n *= -1;
            while (n--) --it;
        }
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Incrementable(decltype(it))>()))
    {
        while (n--)   it;
    }
);

Fonksiyon nesne sürümlerini kullanarak daha küçük, daha kompakt ve okunabilir.

Ayrıca, modeled fonksiyon decltype çirkinlik kısmak için tanımlayabiliriz:

template<class Concept, class... Ts>
constexpr auto modeled(Ts&&...)
{
    return models<Concept(Ts...)>();
}

constexpr const advance = make_conditional(
    STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Advanceable>(it, n)))
    {
        it  = n;
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Decrementable>(it)))
    {
        if (n > 0) while (n--)   it;
        else 
        {
            n *= -1;
            while (n--) --it;
        }
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Incrementable>(it)))
    {
        while (n--)   it;
    }
);

Eğer mevcut kütüphane çözümlerini kullanarak ilgilenen varsa son olarak, (yerine gösterdiğim gibi kendi rolling). Kavramlarının tanımı ve sınırlanması şablonları için bir çerçeve sağlar Tick kütüphane var. Ve Fit kütüphane işlevleri ve aşırı işleyebilir.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Kanaal van Dj0fifty

    Kanaal van D

    28 EKİM 2011
  • Edge-CGI 3D Tutorials and more!

    Edge-CGI 3D

    11 HAZİRAN 2013
  • george sarintzotis

    george sarin

    2 Aralık 2007