2016-04-12 27 views
3

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

+2

sadece uygulamaya bakmak olmaz mı? –

+0

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. –

+0

@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

cevap

6

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.

+1

Güzel çalışır. Teşekkür ederim! – andybuckley

4

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.

0

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...>>; 

DEMO

+0

ah, yazım hatası yaşadım. Sabit düşündüm! – Yakk

+0

@Yakk Onaylandı. –

+0

Bu gerçekten yeni bir cevap değil, Yakk'ta bir yazım hatası yaşadığına dair bir yorum mu var? – Barry