2013-08-20 11 views
5

Esiste, o come scriveresti, una classe metafunzione che verifica se una classe è compatibile con boost::range? Voglio usare il boost::enable linguaggio, qualcosa di simile aMetafunzione per verificare se l'oggetto è compatibile con il range di boost

template <typename T> 
Constructor::Constructor(const T& t, __attribute__((unused)) typename boost::enable_if<is_range_compatible<T> >::type* aux=NULL) 

per un adeguato is_range_compatible metafunction. So di is_container da pretty_print, che cattura molti casi, ma non tutto ciò che funziona con boost::range.

Modifica Questo utilizza C++ 03, quindi non ho accesso alle funzionalità di C++ 11. Sto usando un vecchio, gcc 4.1 e boost 1.51.

+0

Boost ha già una soluzione: [. Concepts controllo] (http://www.boost.org/doc/ libs/1_54_0/libs/range/doc/html/range/concepts/concept_checking.html) – jrok

+1

Sembra essere simile a [questa domanda] (http://stackoverflow.com/questions/14439479/detecting-whether-something-is -Boost-gamma-con-sfinae). – llonesmiz

+0

Hai accesso a C++ 11 o no? Perché la meta-programmazione è leggermente più semplice con 'decltype' e ritorni specificati in ritardo. –

risposta

0

Intendi enable_if?

Se è possibile convincere i controlli di concetto Boost a funzionare utilmente con esso (anziché l'errore di compilazione macro + che utilizza ora), i controlli come ForwardConceptRange sono already provided.

Altrimenti, è un problema utilizzare la macro BOOST_CONCEPT_ASSERT esistente?

+0

Volevo usare SFINAE (un nome che ho appreso solo vedendo il duplicato suggerito), che non ho capito. Una delle cose belle di 'boost :: range' è che può prendere cose come coppie di iteratori, che non funzionerò con i controlli di boost, anche se non li capisco molto bene. –

+0

Esiste in particolare una serie di controlli del concetto di boost per intervalli, aggiungerò un collegamento. Anche se, come ho detto, non sembrano funzionare fuori dagli schemi con SFINAE. – Useless

+0

... fatto, anche se ho appena notato che jrok offriva già lo stesso link. Se 'has_range_const_iterator' lavora per te, sarà più facile comunque. – Useless

0

Se si esegue l'aggiornamento a Boost 1.54, c'è una bella libreria chiamata TTI. Ti consente di comporre a piacere le meta funzioni di introspezione di caratteri di tipo, in modo da poter facilmente estrarre i tuoi metastati che possono essere utilizzati per abilitare o disabilitare i modelli di funzione. Anche se è un bel esercizio di programmazione meta, non consiglio di farlo nel codice di produzione. Ho trovato difficile catturare i "falsi negativi" che derivano dai dettagli di implementazione dei contenitori STL. Ad esempio, i contenitori associativi in ​​arrivo con MSVC11 ereditano le loro funzioni membro begin e end da una classe base che produce un falso negativo con i meta predicati generati tramite BOOST_TTI_HAS_MEMBER_FUNCTION. Nonostante il suo soprannome, Useless ti ha dato un buon consiglio: usa concetti che arrivano con Boost.Range per rifiutare o accettare il tipo all'interno del corpo del modello di funzione come il costruttore nel tuo esempio ... Naturalmente, questo non risolverà il problema problema della convertibilità per il vostro Constructor ...

EDIT: ad esempio, tratto da vex:

#include <boost/tti/has_member_function.hpp> 
#include <vector> 
#include <map> 

namespace tti_test { 
    BOOST_TTI_HAS_MEMBER_FUNCTION(begin); 

    // .. begin test class for mstest 

    // this succeeds in both variants 
    TEST_METHOD(has_const_member_function_begin_is_true_for_vector) 
    { 
     Assert::IsTrue(has_member_function_begin< 
      std::vector<int>::const_iterator (std::vector<int>::*)() const 
     >::value); 

     Assert::IsTrue(has_member_function_begin< 
      const std::vector<int>, std::vector<int>::const_iterator 
     >::value); 
    } 

    // this fails in both variants... 
    TEST_METHOD(has_const_member_function_begin_is_true_for_map) 
    { 
     Assert::IsTrue(has_member_function_begin< 
      std::map<int, int>::const_iterator (std::map<int, int>::*)() const 
     >::value); 

     Assert::IsTrue(has_member_function_begin< 
      const std::map<int, int>, std::map<int, int>::const_iterator 
     >::value); 
    } 

    // end test class for mstest 
}