2012-11-10 10 views
6

Jestem świadkiem zachowania w następującym kodzie, którego nie rozumiem. Chodzi o to, że jeśli Oświadczam drugiego przeciążenie operator() jak jedną z następujących czynności:boost :: variant - Dlaczego parametr szablonu ma wyższy priorytet niż parametr ciągu stałego

bool operator()(T other) const 
bool operator()(const T &other) const 

Wyjście programu jest:

ciąg

Ale jeśli mogę użyć następujących deklaracja:

bool operator()(T &other) const 

Dane wyjściowe będą następujące:

inny rodzaj

Czy ktoś mógłby wyjaśnić, dlaczego operator()(const string &other) nie jest nazywany w tym ostatnim przypadku?

#include "boost/variant/variant.hpp" 
#include "boost/variant/apply_visitor.hpp" 

using namespace std; 
using namespace boost; 

typedef variant<string, int> MyVariant; 


class StartsWith 
    : public boost::static_visitor<bool> 
{ 
public: 
    string mPrefix; 
    bool operator()(const string &other) const 
    { 
     cout << "string" << endl; 
     return other.compare(0, mPrefix.length(), mPrefix) == 0; 
    } 
    template<typename T> 
    bool operator()(T &other) const 
    { 
     cout << "other type" << endl; 
     return false; 
    } 
    StartsWith(string const& prefix):mPrefix(prefix){} 
}; 

int main(int argc, char **argv) 
{ 
    MyVariant v(string("123456")); 
    apply_visitor(StartsWith("123"), v); 
    return 0; 
} 

Odpowiedz

5

Masz tutaj problem z const.

Przekazujesz nie stały obiekt do apply_visitor - więc nie elementy const const są przekazywane do stosowanego gościa. Tak więc w twoim przypadku jest to string& - odniesienie do typu łańcucha. Ten szablon jest dokładnie zgodny z tym:

template<typename T> 
bool operator()(T &other) const 

Został wybrany. Ta funkcja nie jest dokładne dopasowanie - to jest pomijany:

bool operator()(const string &other) const 

Oczywiście jeśli zapewniają, że operator:

bool operator()(string &other) const 

to będzie wybrany, ponieważ nie są uważane funkcja szablon przed jednym szablonie.

Więc rozwiązaniem jest: albo zapewnić metodę w swoim gościem, który trwa odniesienie ciągu (nie const) - lub przekazać const wariant zastosowania ...

pierwsze rozwiązanie - usunąć const od operatora strun:

bool operator()(/*const*/ string &other) const 
//    ^^^^^^^^^ remove it 

drugie rozwiązanie - przechodzą const obiektu:

const MyVariant& cv = v; 
apply_visitor(StartsWith("123"), cv); 
//        ^^ const object passed here 

trzecie rozwiązanie - dodaje specyfikator const do ogólnej odwiedzającego:

template<typename T> 
bool operator()(const T &other) const 
//    ^^^^^ 

Rozwiązania 1 i 3 są lepsze niż 2 - należy przejść spójnego gościa do swojego wariantu, const ma silne znaczenie, gdy kompilator musi wybrać odpowiednią funkcję.

+0

Jako maniak typu, powiedziałbym, że rozwiązanie ** 3rd ** to ** best **, as-in: ** const-correct **. Nie ma powodu, aby przyjmować parametr przez odniesienie do stałych, jeśli nie zamierzasz go modyfikować. –

+0

@ MatthieuM. W tym przypadku masz rację.Nie wspomniałem o "T &&" - prawdopodobnie byłby najlepszy - ale jest wiele postów w SO mówiących o różnicy między 'T &&' i' const T & ', więc nie chciałem tworzyć tu niepotrzebnego miksu ... – PiotrNycz

Powiązane problemy