2015-05-19 11 views
10

Ho una classe con un parametro template e voglio chiamarne un metodo. Sembra qualcosa di simile:Come rendere un metodo const basato sul parametro template?

template <typename T> 
class Foo { 
public: 
    void doSomething() { 
     for (auto& t: ts) { 
      t.doSomething(); 
     } 
    } 
private: 
    std::vector<T> ts; 
}; 

Questo funziona, ma voglio fare doSomething() const se T stessa è const (si presume che T::doSomething() sarà const troppo). Ho trovato una possibile soluzione (basata su this question), ma non mi piace.

template <bool enabled = std::is_const<T>::value> 
typename std::enable_if<enabled, void>::type 
doSomething() const { 
    for (auto& t: ts) { 
     t.doSomething(); 
    } 
} 

template <bool enabled = !std::is_const<T>::value> 
typename std::enable_if<enabled, void>::type 
doSomething() { 
    for (auto& t: ts) { 
     t.doSomething(); 
    } 
} 

Funziona bene, ma ha una duplicazione del codice. C'è un modo per evitarlo?

+0

Come workarround si potrebbe aggiungere 'privato: attributo (always_inline) _doSomething' e chiamare che dal' (const) dosomething' – ted

risposta

2

Anche se non perfetto ecco una soluzione: abbiamo un membro non const _doSomething() in cui abbiamo il codice che è lo stesso per const e non const, ad eccezione della funzione chiamata sull'oggetto sottostante. Poiché questo membro è non const dobbiamo const_castthis chiamarlo da un const Foo.

Poiché il codice all'interno di _doSomething è const safe, è sicuro di (const_) eseguire il cast const.

Il tuo codice non verrà compilato per const, dal momento che non puoi avere un vector di const. Gli elementi di un vettore devono essere assegnabili, che const types sono in genere non (in realtà non dovrebbero, tuttavia: https://stackoverflow.com/a/17313104/258418).
Si potrebbe prendere in considerazione std::vector<T*> anziché std::vector<T>. (IE negozio puntatori piuttosto che gli oggetti del vettore)

#include <iostream> 
#include <vector> 

using namespace std; 

class Bar { 
public: 
    Bar() {} 
    void doSomething() const { 
     std::cout << "const" << endl; 
    } 

    void doSomething() { 
     std::cout << "NON const" << endl; 
    } 
}; 


template <typename T> 
class Foo { 
    void _doSomething() { 
     /*for (auto& t: ts) { 
      t.doSomething(); 
     }*/ 
     test.doSomething(); 
    } 
public: 
    Foo()/*T element) : ts({element})*/ {} 

    template <bool enabled = std::is_const<T>::value> 
    typename std::enable_if<enabled, void>::type 
    doSomething() const { 
     const_cast<typename std::remove_const<Foo<T>>::type*>(this)->_doSomething(); 
    } 

    template <bool enabled = !std::is_const<T>::value> 
    typename std::enable_if<enabled, void>::type 
    doSomething() { 
     _doSomething(); 
    } 
private: 
    //std::vector<T> ts; https://stackoverflow.com/a/17313104/258418 
    T test; 
}; 

int main() 
{ 
    Foo<Bar> nonConstInst; 
    Foo<const Bar> ConstInst; 

    nonConstInst.doSomething(); 
    ConstInst.doSomething(); 
    return 0; 
} 
+1

vero, doesn' t lavoro per il vettore. In realtà sto usando 'shared_ptr' (' unique_ptr' sarebbe meglio), quindi la funzione const funzionerebbe sempre. Tuttavia, gli oggetti contenuti sono parte dello stato dell'oggetto, quindi voglio che 'doSomething()' sia non-const se sto cambiando lo stato degli oggetti contenuti. Ma comunque la tua soluzione funziona e non ho nemmeno dovuto 'const_cast'. – petersohn

Problemi correlati