2016-06-06 13 views
5

Nota: tutto ciò che segue utilizza l'implementazione Concetti TS in GCC 6.1definizione Concetto che richiede una funzione di membro template vincolata

Diciamo che ho un concetto Surface, come il seguente:

template <typename T> 
concept bool Surface() { 
    return requires(T& t, point2f p, float radius) { 
     { t.move_to(p) }; 
     { t.line_to(p) }; 
     { t.arc(p, radius) }; 
     // etc... 
    }; 
} 

Ora Voglio definire un altro concetto, Drawable, che corrisponde a qualsiasi tipo con una funzione membro:

template <typename S> 
    requires Surface<S>() 
void draw(S& surface) const; 

cioè

struct triangle { 
    void draw(Surface& surface) const; 
}; 

static_assert(Drawable<triangle>(), ""); // Should pass 

Cioè, un Drawable è qualcosa che ha una funzione template membro const draw() prendendo un riferimento lvalue a qualcosa che soddisfi i requisiti Surface. Questo è ragionevolmente facile da specificare a parole, ma non riesco a capire come farlo in C++ con TS Concetti. La sintassi "ovvio" non funziona:

template <typename T> 
concept bool Drawable() { 
    return requires(const T& t, Surface& surface) { 
     { t.draw(surface) } -> void; 
    }; 
} 

error: 'auto' parameter not permitted in this context

aggiunta di un secondo parametro di modello permette di definire il concetto di compilare, ma:

template <typename T, Surface S> 
concept bool Drawable() { 
    return requires(const T& t, S& s) { 
     { t.draw(s) }; 
    }; 
} 

static_assert(Drawable<triangle>(), ""); 

template argument deduction/substitution failed: couldn't deduce template parameter 'S'

ora possiamo solo controllare se un particolare < Drawable, Surface>coppia corrisponde al concetto Drawable, che non è corretto. (Un tipo D ha la funzione membro richiesta o non lo fa: che non dipende da quale particolare Surface controlliamo.)

Sono sicuro che è possibile fare ciò che sto cercando, ma io posso t calcoliamo la sintassi e non ci sono ancora troppi esempi online. Qualcuno sa come scrivere una definizione di concetto che richiede che il tipo abbia una funzione membro modello vincolata?

+0

Hai provato a usare std :: is_member_function_pointer all'interno della definizione di concetti? Potrebbe funzionare. Impossibile verificare qui perché non ho installato gcc al lavoro ... – gilgamash

+2

Probabilmente lo stesso come http://stackoverflow.com/questions/23659382/specifying-a-concept-for-a-type-that-has-a- membro-function-template-con-concep? RQ = 1 – ecatmur

risposta

2

Quello che stai cercando è un modo per il compilatore di sintetizzare un archetipo di Surface. Cioè, un tipo privato, anonimo che soddisfa in minima parte il concetto Surface. Il più minimamente possibile. Concetti TS al momento non consente un meccanismo per la sintesi automatica degli archetipi, quindi non ci resta che farlo manualmente. È piuttosto un complicated process, dal momento che è molto facile trovare candidati all'archetipo che hanno più funzionalità che il concetto specifica.

In questo caso, possiamo venire con qualcosa di simile:

namespace archetypes { 
    // don't use this in real code! 
    struct SurfaceModel { 
     // none of the special members 
     SurfaceModel() = delete; 
     SurfaceModel(SurfaceModel const&) = delete; 
     SurfaceModel(SurfaceModel&&) = delete; 
     ~SurfaceModel() = delete; 
     void operator=(SurfaceModel const&) = delete; 
     void operator=(SurfaceModel&&) = delete; 

     // here's the actual concept 
     void move_to(point2f); 
     void line_to(point2f); 
     void arc(point2f, float); 
     // etc. 
    }; 

    static_assert(Surface<SurfaceModel>()); 
} 

E poi:

template <typename T> 
concept bool Drawable() { 
    return requires(const T& t, archetypes::SurfaceModel& surface) { 
     { t.draw(surface) } -> void; 
    }; 
} 

questi sono concetti validi, che, probabilmente, funzionano. Si noti che c'è molto spazio per un ulteriore perfezionamento sull'archetipo SurfaceModel. Ho una funzione specifica void move_to(point2f), ma il concetto richiede solo che sia richiamabile con un lvalue di tipo point2f.Non c'è alcun requisito che move_to() e line_to() sia prendere un argomento di tipo point2f, potrebbero entrambi prendere le cose complete diverse:

struct SurfaceModel {  
    // ... 
    struct X { X(point2f); }; 
    struct Y { Y(point2f); }; 
    void move_to(X); 
    void line_to(Y); 
    // ... 
}; 

Questo tipo di paranoia fa per un archetipo di meglio, e serve ad illustrare la complessità di questo problema potrebbe essere .