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
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.
İletişim atma "pencereyi simge bo...
Neden belgedir.yazma " kabul;kötü ...
Quot; hedef cihazda hiçbir Şey olmuyor...
Facebook API - Nasıl Facebook kullanıc...
Böyle büyük mükafat 4 bağlantı &; Ekle...