2015-08-27 16 views
5

Desidero consentire l'uso di std :: function nel mio codice base se non esegue alcuna allocazione.catch std :: allocazioni di funzioni al momento della compilazione

A tal fine posso scrivere qualcosa di simile la funzione qui sotto e utilizzarla solo per creare le mie istanze di funzione:

template< typename Functor> 
std::function<Functor> makeFunction(Functor f) 
{ 
    return std::function<Functor>(std::allocator_arg, DummyAllocator(), f); 
} 

dove DummyAllocator affermerà o buttare se mai si abitua in fase di esecuzione.

Idealmente, tuttavia, vorrei prendere in considerazione i casi di utilizzo allocati in fase di compilazione.

cioè

template< typename Functor> 
std::function<Functor> makeFunction(Functor f) 
{ 
    static_assert(size needed for function to wrap f < space available in function, 
    "error - function will need to allocate memory"); 

    return std::function<Functor>(f); 
} 

è qualcosa di simile possibile?

+3

Non credo che l'ottimizzazione piccolo oggetto è esposto in 'std :: function', basandosi su di essa si tradurrà in codice non portabile in ogni caso. Per esempio. libC++ usa un buffer della dimensione di 3 'void *', che è diverso sui sistemi 32 vs 64 bit x86. libC++ usa 'sizeof (__ buf_)' per verificare se il SOO deve essere applicato, e non riesco a trovare alcuna funzione in cui questa informazione è esposta. – dyp

+0

@dyp Bene, il codice stesso è portatile. Compilerà e produrrà risultati attesi su tutte le piattaforme. Se l'idea è di consentire solo l'uso di std :: function non allocante, non importa cosa (e posso vedere alcuni scenari ragionevoli che lo richiedono) questo è un approccio ragionevole. Assegnare allocazioni al momento della compilazione non è possibile, dal momento che non si verificano in fase di compilazione. – SergeyA

+0

@SergeyA Beh, è ​​possibile catturarli in fase di compilazione se il codice rimanente del codificatore era constexpr, ma ciò non è possibile con SOO perché deve utilizzare placement-new. Il mio commento sulla portabilità era più che altro un tentativo di spiegare * perché * non è esposto. Anche 'int x = 1 << 17;' è un codice non portatile, e sono certamente d'accordo che la nonportabilità nell'OP sia del tipo migliore (errore del compilatore). – dyp

risposta

2

Il metodo di fabbrica che hai è probabilmente la soluzione migliore.

Se non adatto, è possibile scegliere di implementare un adattatore per function; implementare l'interfaccia con lo std::function come variabile membro in modo tale che l'adattatore imponga i propri vincoli.

template <typename S> 
class my_function { 
    std::function<S> func_; 
public: 
    template <typename F> 
    my_function(F&& f) : 
    func_(std::allocator_arg, DummyAllocator(), std::forward<F>(f)) 
    {} 
    // remaining functions required include operator()(...) 
}; 
0

Dato il supporto di allocatore std::function nella libreria, fornire semplicemente std::function con un allocatore che non funziona.

template< typename t > 
struct non_allocator : std::allocator<t> { 
    t * allocate(std::size_t n) { throw std::bad_alloc{}; } 
    void deallocate(t *) {} 

    non_allocator() = default; 
    template< typename u > 
    non_allocator(non_allocator<u> const &) {} 

    template< typename u > 
    struct rebind { typedef non_allocator<u> other; }; 
}; 

template< typename t, typename u > 
bool operator == (non_allocator<t> const &, non_allocator<t> const &) 
    { return true; } 

template< typename t, typename u > 
bool operator != (non_allocator<t> const &, non_allocator<t> const &) 
    { return false; } 

Purtroppo, questo non funziona in GCC, perché non ha nemmeno dichiarare qualsiasi allocator_arg costruttori per function. Anche in Clang, un errore in fase di compilazione è impossibile perché purtroppo utilizza un runtime if su un valore costante per decidere se utilizzare o meno l'allocatore.

2

Scriverò una sostituzione std::function che non alloca, poiché std::function assegna memoria se necessario, ecco uno candidate.

Problemi correlati