2012-11-07 16 views
14

Üç tür kabul eden boost::variant bildirdim: string, bool ve int. Aşağıdaki kod benim varyantımın const char* kabul ettiğini ve bool'a dönüştürdüğünü gösteriyor. Listesinde olmayan türleri kabul etmek ve dönüştürmek boost::variant için normal bir davranış mı?boost :: variant - neden "const char *" "bool" olarak dönüştürülür?

#include <iostream> 
#include "boost/variant/variant.hpp" 
#include "boost/variant/apply_visitor.hpp" 

using namespace std; 
using namespace boost; 

typedef variant<string, bool, int> MyVariant; 

class TestVariant 
    : public boost::static_visitor<> 
{ 
public: 
    void operator()(string &v) const 
    { 
     cout << "type: string -> " << v << endl; 
    } 
    template<typename U> 
    void operator()(U &v)const 
    { 
     cout << "type: other -> " << v << endl; 
    } 
}; 

int main(int argc, char **argv) 
{ 
    MyVariant s1 = "some string"; 
    apply_visitor(TestVariant(), s1); 

    MyVariant s2 = string("some string"); 
    apply_visitor(TestVariant(), s2); 

    return 0; 
} 

çıkışı:

türü: Diğer -> 1
türü: dize -> Bazı dize

Ben MyVariant gelen bool türü kaldırmak ve bu onu değiştirirseniz:

typedef variant<string, int> MyVariant; 

const char*bool'a dönüştürülmez. Bu sefer string dönüştürülmediği ve bu yeni çıkışı:

türü: dize -> Bazı dize
türü: dize -> Bu variant çalışır diğer türleri dönüştürmek olduğunu gösterir bazı dize

önce bool ve sonra string. Tür dönüşümü kaçınılmaz bir şeyse ve her zaman yapılmalıysa, string'a daha yüksek bir öncelik vermenin herhangi bir yolu var mı?

cevap

10

Bunun özellikle boost::variant ile ilgili bir şey olduğunu sanmıyorum, aşırı yüklenme tarafından hangi kurucunun seçileceği hakkında.

#include <iostream> 
#include <string> 

void foo(bool) { 
    std::cout << "bool\n"; 
} 

void foo(std::string) { 
    std::cout << "string\n"; 
} 

int main() { 
    foo("hi"); 
} 

çıktı:

bool 

Bir Varyantı [neler yapıcıları değiştirmek için bir yol bilmiyorum düzenleme: James dediği gibi yazabilirsiniz aynı şey bir aşırı fonksiyonu ile olur Varyantı uygulamasında kullanan başka bir sınıf. Daha sonra, doğru olanı yapan bir const char* yapıcı sağlayabilirsiniz.]

Belki de türleri Değişken'de değiştirebilirsiniz. Başka aşırı örnek:

struct MyBool { 
    bool val; 
    explicit MyBool(bool val) : val(val) {} 
}; 

void bar(MyBool) { 
    std::cout << "bool\n"; 
} 

void bar(const std::string &) { 
    std::cout << "string\n"; 
} 

int main() { 
    bar("hi"); 
} 

çıkışı:

string 

Maalesef şimdi bar(MyBool(true)) yerine foo(true) yazmak zorunda. Varyantınızın string/bool/int ile daha da kötü olması durumunda, string/MyBool/int'un bir varyantına değiştirirseniz, MyVariant(true)int yapıcısını çağırır.

+6

Açıklamanızı tamamlamak için: herhangi bir işaretçi türünden "bool" değerine örtülü bir dönüşüm var ve yerleşik tanımlı dönüşümler her zaman kullanıcı tanımlı dönüşümler için tercih edilir. Kurucular değişen gelince, başka bir sınıfta sınıf kaydırmak veya ondan türetebilirsiniz (kullanıcı tanımlı. olarak 'std :: string' sayımları dönüşüm' Char * '). Bağlamıza bağlı olarak bunlardan biri uygun olabilir veya olmayabilir; her ikisi de bazı dezavantajları var. –

+0

Bir çözüm MyVariant' 'dan' bool' çıkarmak ve bunun yerine, 0 ve 1 değerleri kullanmak olduğunu düşünüyorum. – Meysam

+0

@Meysam: evet. Bunu öneren düşündü ama sonra muhtemelen 'FALSE' ile başlatıldı MyVariant' farklı olduğu '0' ile başlatıldı bir' MyVariant' istediğini sanıyordum. Onların aynı olması için sorun varsa, sadece 'bool' kaldırın. Farklı anlamları varsa, o kadar basit değil. –

9

Bu, boost::variant ile ilgisi yoktur, ancak C++ uygulamasının uygulanacak dönüşümleri seçtiği sırayla. Kullanıcı tanımlı dönüşümleri kullanmaya başlamadan önce (bu amaç için std::string kullanıcı tanımlı bir sınıf olduğunu unutmayın), derleyici yerleşik dönüşümleri deneyecektir.Orada const char* den int için yerleşik bir dönüşüm, ancak standart §4.12 e göre

[...] işaretçi [...] tip tip bir prvalue dönüştürülebilir bir prvalue bool.

Yani derleyici mutlu senin const char*bool bir dönüşür ve asla bir std::string dönüştürerek dikkate alır.

+0

Bu, bugün bir çift aşırı yüklenmiş yöntemle beni ısırdı, biri bool, diğeri ise const std :: string & '. Talihsiz! – davidbak

İlgili konular