boost::any 混淆指针与值

boost::any confusion with pointers vs values

我花了一段时间才弄明白,但是 boost::any 的语义令人困惑。

对于值类型,你可以这样使用它:

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

此代码清晰且有意义,但在内部存储 value 作为副本。这意味着对于我放在 boost::any 中的较大对象,它们将被复制。此外,我用此替换 void* 的任何函数都希望在我修改 boost::any 对象中包含的值时修改函数外部的值(这不会发生,因为它复制了它)。

因此,如果我将指针放入其中,事情就会变得很奇怪:

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

在这种情况下,我必须取消引用 return 值,因为 boost::any_cast returns int**!我也没有检查过,但我认为如果 something.empty() == true 这可能会崩溃。这一点都不简单。

我不想在我的 boost::any 中存储值,我希望它只对指针起作用并且在语义上更接近 void*。指针输入,指针输出,混合了一些类型安全。本质上我想要的是 boost::any_pointer 或类似的东西。有没有办法禁止 boost::any 接受指针以外的任何东西?如果没有,是否有 boost::any 的替代方案可以提供我正在寻找的语义?

注意:我假设您想将指针存储在 boost::any 中,因为您正在寻找 boost::any_pointer 中的内容(尽管不是-存在)。

boost::any_cast returns 指向存储在其中的实际值的指针(holder 中的 held 对象)。所以它会保存一个副本,除非你以后真的想复制它。

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

您始终可以围绕 boost::any 创建一个包装器以仅允许指针类型:

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

以上是粗略的代码,我还没有编译测试

std::enable_if 类型特征在 C++11 中可用,但也可以在 boost 中找到。这就是将 MyAny 限制为仅指针类型的原因。

您使用的 any_cast 错误:

基本上有两(三)种口味。

  • 引用任何内容并返回值或引用内容
  • 获取指向任何内容的指针并返回指向内容的指针

示例:

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

另请参阅:http://en.cppreference.com/w/cpp/experimental/any and http://en.cppreference.com/w/cpp/experimental/any/any_cast

虽然这是一个很老的问题,但我还是想指出一个简单的误解 [我认为] 在问题的前言中:

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

1) 这节省了 "int *" 的东西。

2) 这主要包含几个步骤:

  • "&something" 获取某物的地址,即 return "boost::any *"
  • "boost::any_cast()" 现在将此地址转换为指向 int 的指针 - 这可能不是 void.pointer 想要的。而且我不知道是否 - 如果,为什么 - 这似乎有效。
  • 然后取消对“*boost::...”的引用,即再次取消第一步中的“&”。

我想,void.pointer 想在这里做的,更多的是沿着以下路线:

int* value = boost::any_cast<int*>(something);

.

PS:我本来想把它放在一个简单的评论中,而不是一个完整的答案 - 但是 Whosebug 要求我先收集足够的点数,所以...