Boost'un SFINAE yardımcılarının birçoğu, C++ 11 ile std kitaplığında görünmüştür, ancak has_dereference
görünmüyor. Bu özellikten başka, paketimin bir Boost bağımlılığını ortadan kaldırmayı başardım ve tamamen kurtulmak istiyorum, bu yüzden sadece C++ 11 std özelliklerini kullanarak aynı etkiyi elde etmek için en iyi yolu nedir?C++ 11 std eşdeğeri Boost has_dereference
cevap
Bir sınıfın harici bağımlılıkları olmayan bir işlevi olup olmadığını kontrol etmenin en kolay yolu genellikle void_t
deyimindedir.
// Define this once in your project somewhere accessible
template <class ... T>
using void_t = void;
Bu numara her zaman aynıdır;
template <class T, class = void>
struct has_dereference : std::false_type {};
Bu "son çare" sınıfı şablonu şudur: std::false_type
dan devralan bir sınıf şablonu tanımlar.
template <class T>
struct has_dereference<T, void_t<decltype(*std::declval<T>())>> : std::true_type {};
kullanmak için sadece yapın:: Şimdi sadece tip özelliğine sahiptir zaman istediğimiz çalışan bir ihtisas tanımlayacağız
bool x = has_dereference<int*>::value;
bool y = has_dereference<int>::value;
vb
Ben katacak teknik olarak, operator*
aslında bir fonksiyon ailesidir; Operatör hem nitelikli CV hem de değer kategorisi olabilir. Bir tür üzerinde algılama gerçekleştirdiğinizde, aslında bu aile içinde algılama yapıyorsunuz demektir. Uygulamada nadiren karşılaştığım için daha fazla ayrıntıya girmeyeceğim (operator*
, nadiren kategori niteliğinde niteliklidir ve operatör hemen hemen her zaman bir const versiyonuna sahiptir ve nadiren uçucu), ama şaşırtıcı bir şey gördüğünüzde bunun farkında olmanız gerekir. .
Bu teknik, özellikle de Boost veya Hana gibi bağımlılıklar olmadan meta-programlama yapıyorsanız bunu bilmeye değer. Void_t hakkında daha fazla bilgiyi buradan edinebilirsiniz: How does `void_t` work.
Güzel çalışır. Teşekkür ederim! – andybuckley
Bu, küçük bir SFINAE özelliği yazma yardımcısıdır. Eğer eksikse yeniden oluşturabileceğiniz std::void_t
kullanır.
namespace details {
template<template<class...>class Z, class v, class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=typename details::can_apply<Z, void, Ts...>::type;
Bunu bir kez yaptınız, sorunlarınız kolay.
template<class T>
using deref_result = decltype(*std::declval<T>());
template<class T>
using can_deref = can_apply<deref_result, T>;
buradaki fikir std::void_t
makine saklamaktır. "Bazı hesaplamaların sonucunu" ifade eden bir özellik yazıyorsunuz ve bundan "hesaplamanın geçerli olduğu" alabiliyoruz. tek satırda yapıyor
namespace details {
template<class...>struct voider{using type=void;};
}
template<class...Ts>
using void_t=typename voider<Ts...>::type;
bazı eski derleyiciler kırar ve 2 çizgi versiyonu olabilir, hem de yeterince kolaydır: gibi
Son derece portatif void_t
görünüyor.
Yakk 'ın değişik bir versiyonu:
template <class...> struct pack {};
namespace detail {
template<template <class...> class Z, class Pack, class = void>
struct can_apply_impl : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply_impl<Z, pack<Ts...>, std::void_t<Z<Ts...>> > : std::true_type {};
}
template<template<class...>class Z, class...Ts>
using can_apply = detail::can_apply_impl<Z, pack<Ts...>>;
sadece uygulamaya bakmak olmaz mı? –
Lisansı tam olarak bilmiyorum, ancak muhtemelen Boost uygulamasını yapıştırmak için kod yazabilirsiniz.Sadece başlık olmalı ve çok uzun değil. –
@Nicol Sanırım yapmadın mı? ;-) Dahili bir has_prefix_operator.hpp üstbilgisi tarafından kullanılan ve daha sonra yeniden tanımlanmamış olan BOOST_TT_FORBIDDEN_IF gibi gizli (ve karmaşık görünümlü) #defines ile yapılır. Bu yüzden tersine mühendislik yapmak ve kesinlikle sadece Boost kodunun std tabanlı kodlara kopyalanması meselesi değil. – andybuckley