2016-06-13 4 views
0

Il m'a fallu du temps pour le comprendre, mais la sémantique de boost::any est confuse.boost :: toute confusion avec les pointeurs et les valeurs

Avec les types de valeur, vous l'utilisez comme ceci:

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

Ce code est clair et logique, mais les magasins value en interne comme une copie. Cela signifie que pour les objets plus grands que je place à l'intérieur boost::any, ils seront copiés. Aussi toutes les fonctions que je remplace void* avec ceci s'attendent à ce que la valeur en dehors de la fonction soit modifiée lorsque je modifie la valeur contenue dans l'objet boost::any (ce qui n'arrivera pas, puisqu'il l'a copié).

Donc, si je mets des pointeurs en elle, les choses deviennent étranges:

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

Je dois déréférencer la valeur de retour dans ce cas parce que boost::any_cast retours int**! Je n'ai pas non plus vérifié mais je pense que cela peut planter si something.empty() == true. Ce n'est pas simple du tout.

Je ne veux pas stocker de valeurs dans mon boost::any, je veux qu'il ne fonctionne que sur les pointeurs et se comporte sémantiquement plus proche de void*. Pointeurs dans, pointeurs, avec un certain type de sécurité mélangé po Essentiellement ce que je veux est boost::any_pointer, ou quelque chose comme ça. Existe-t-il un moyen d'interdire boost::any d'accepter autre chose que des pointeurs? Et sinon, y a-t-il une alternative à boost::any qui peut me donner la sémantique que je recherche?

+0

'boost :: any' est joli e Asy pour créer et ensuite vous pouvez modifier la sémantique comment vous voyez en forme. –

+0

Votre premier extrait ne fonctionne pas et nécessite dereferencement (comme snippet2) [Demo] (http://coliru.stacked-crooked.com/a/df5bdb307f56b709) – Jarod42

+0

Vous pouvez toujours envelopper 'boost :: any' dans une classe à autoriser uniquement le pointeur. – Jarod42

Répondre

1

NOTE: Je suppose que vous voulez stocker des pointeurs dans boost::any, puisque vous cherchez quelque chose sur les lignes de boost::any_pointer (si inexistante).

boost::any_cast renvoie le pointeur vers la valeur réelle stockée à l'intérieur (l'objet held à l'intérieur du support). Donc, il en enregistre une copie à moins que vous ne vouliez vraiment le copier plus tard.

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; 
    } 

Vous pouvez toujours créer une enveloppe autour boost::any pour autoriser uniquement les types de pointeur:

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_ 
}; 

ci-dessus est un code rugueux, je n'ai pas compilé et testé. Type trait est disponible en C++ 11, mais peut également être trouvé dans boost. C'est ce qui va contraindre votre MyAny aux seuls types de pointeurs.

1

Vous utilisez any_cast mal:

Il existe essentiellement deux saveurs (trois).

  • Prendre une référence à un et retourner une valeur ou une référence au contenu
  • Prendre un pointeur sur tout et en retournant un pointeur vers le contenu

Exemples:

#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); 
    } 
} 

Voir aussi: http://en.cppreference.com/w/cpp/experimental/any et http://en.cppreference.com/w/cpp/experimental/any/any_cast

+0

Je vois que cette syntaxe jette beaucoup de monde. C'est la même chose pour std :: any. –

+0

J'essaie d'éviter les exceptions en utilisant 'boost :: any', c'est pourquoi j'utilise la surcharge du pointeur. Vos premier et deuxième exemples semblent être des exceptions. au moins dans mes tests, il l'a fait. –

+0

Voici un exemple que j'ai écrit qui le montre lancer; Je ne veux pas le jeter, je veux un 'nullptr' renvoyé si les types sont faux: http://coliru.stacked-crooked.com/a/f6ffdf4387e335d6 –