2016-06-13 13 views
0

Es dauerte eine Weile, um herauszufinden, aber die Semantik von boost::any sind verwirrend.Boost :: Irgendeine Verwechslung mit Zeigern gegen Werte

Mit Werttypen verwenden Sie es wie so:

int value = 100; 
boost::any something; 
something = value; 
//...later... 
int value = boost::any_cast<int>(&something); 

Dieser Code ist klar und macht Sinn, sondern speichert value intern als Kopie. Das bedeutet für größere Objekte, die ich innerhalb boost::any platziere, werden sie kopiert. Auch alle Funktionen, die ich ersetze void* damit erwarten, dass der Wert außerhalb der Funktion geändert wird, wenn ich den Wert im boost::any Objekt ändern (was nicht passieren wird, da es kopiert).

Wenn ich also Zeiger in sie setzen, werden die Dinge seltsam:

int value = 100; 
boost::any something; 
something = &value; 
//...later... 
int* value = *boost::any_cast<int*>(&something); 

ich zu dereferenzieren den Rückgabewert in diesem Fall, weil boost::any_cast Renditen int**! Ich habe auch nicht überprüft, aber ich denke, dass dies abstürzen kann, wenn something.empty() == true. Das ist einfach nicht einfach.

Ich möchte keine Werte in meinem boost::any speichern, ich möchte, dass es nur auf Zeigern funktioniert und sich semantisch näher an void* verhält. Zeiger hinein, Zeiger raus, mit etwas Typsicherheit gemischt. Im Wesentlichen will ich boost::any_pointer, oder so ähnlich. Gibt es eine Möglichkeit zu verbieten boost::any alles außer Zeigern zu akzeptieren? Und wenn nicht, gibt es eine Alternative zu boost::any, die mir die gesuchte Semantik geben kann?

+0

'boost :: any' ist hübsch e asy zu erstellen und dann können Sie die Semantik ändern, wie Sie es für richtig halten. –

+0

Ihr erstes Snippet funktioniert nicht und erfordert eine Dereferenzierung (als snippet2) [Demo] (http://coliru.stacked-crooked.com/a/df5bdb307f56b709) – Jarod42

+0

Sie können noch "boost :: any" in eine Klasse umwandeln Erlaube nur Zeiger. – Jarod42

Antwort

1

HINWEIS: Ich gehe davon aus Sie in boost::any Zeiger zu speichern, da Sie etwas auf den Linien von boost::any_pointer (wenn auch nicht existent) suchen.

boost::any_cast gibt den Zeiger auf den tatsächlichen Wert zurück, der darin gespeichert ist (held Objekt im Halter). Es speichert also eine Kopie, es sei denn, Sie möchten es später tatsächlich kopieren.

template<typename ValueType> 
    ValueType * any_cast(any * operand) BOOST_NOEXCEPT 
    { 
     return operand && operand->type() == boost::typeindex::type_id<ValueType>() 
      ? &static_cast<any::holder<BOOST_DEDUCED_TYPENAME remove_cv<ValueType>::type> *>(operand->content)->held 
      : 0; 
    } 

Sie können immer einen Wrapper um boost::any erstellen nur Zeigertypen zu ermöglichen:

class MyAny { 
public: 
    template <typename T, 
     typename = typename std::enable_if<std::is_pointer<std::remove_cv<T>::type>::value>::type> 
    MyAny(T ptr): any_(ptr) {} 

template <typename ValueType> 
ValueType operator*() { 
    return *boost::any_cast<ValueType>(&any_); 
} 

private: 
    boost::any any_ 
}; 

Oben ist ein grober Code, habe ich nicht kompilierte und getestet.

std::enable_if Typ Merkmal ist in C++ 11 verfügbar, kann aber auch in Boost gefunden werden. Es ist, was das Ihre MyAny nur zu Zeigertypen einschränkt.

1

Sie verwenden any_cast falsch:

Es gibt im Wesentlichen zwei (drei) Aromen.

  • eine Bezugnahme auf die Einnahme und einen Wert oder auf den Inhalt
  • Einen Zeiger auf jede der Rückkehr und einen Zeiger auf den Inhalt

Beispiele Rückkehr:

#include <boost/any.hpp> 
int main() 
{ 
    // Any holding a value 
    { 
     boost::any any_value(1); 
     // Throws bad_any_cast if the content is not 'int' (in this case): 
     int value = boost::any_cast<int>(any_value); 
     // Throws bad_any_cast if the content is not 'int' (in this case): 
     int& reference = boost::any_cast<int&>(any_value); 
     // Returns a null pointer if the content is not 'int' (in this case): 
     int* pointer = boost::any_cast<int>(&any_value); 
    } 

    // Any holding a pointer (which is nothing else but a value) 
    { 
     int integer = 0; 
     boost::any any_ptr(&integer); 
     // Throws bad_any_cast if the content is not 'int*' (in this case): 
     int * pointer = boost::any_cast<int*>(any_ptr); 
     // Throws bad_any_cast if the content is not 'int*' (in this case): 
     int*& pointer_reference = boost::any_cast<int*&>(any_ptr); 
     // Returns a null pointer if the content is not 'int*' (in this case): 
     int** pointer_pointer = boost::any_cast<int*>(&any_ptr); 
    } 
} 

Siehe auch: http://en.cppreference.com/w/cpp/experimental/any und http://en.cppreference.com/w/cpp/experimental/any/any_cast

+0

Ich sehe, dass Syntax eine Menge Leute abwerfen. Das gleiche gilt für std :: any. –

+0

Ich versuche, Ausnahmen zu vermeiden, während ich 'boost :: any' benutze, weshalb ich die Zeigerüberladung verwende. Ihr erstes und zweites Beispiel scheinen Ausnahmen zu werfen; zumindest in meinen Tests hat es getan. –

+0

Hier ist ein Beispiel, das ich geschrieben habe, das es wirft zeigt; Ich will nicht, dass es zu werfen, ich will ein 'nullptr' zurückgegeben, wenn die Typen falsch sind: http://coliru.stacked-crooked.com/a/f6ffdf4387e335d6 –