【发布时间】:2014-03-27 12:29:09
【问题描述】:
我有以下(非常简化的)“容器”类:
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
它应该以共享指针的形式将对象存储在boost::any 容器中。如果我在容器中存储一些 boost::shared_ptr<some_type> 类型的对象,我想通过用户定义的转换来获取引用 (const some_type&),这将允许执行以下操作:
boost::shared_ptr<some_type> x(new some_type);
container cx = x;
...
// user-defined conversion
const some_type &y = cx;
// a template conversion using a "getter"
const some_type &y = cx.get<some_type>();
有时,我需要存储从某个抽象类型派生的对象,并对该抽象类型的引用进行相同类型的类型转换,例如,像这样:
boost::shared_ptr<some_abstract_type> x(new some_derived_type);
container cx = x;
...
// user-defined conversion
const some_abstract_type &y = cx;
// a template conversion using a "getter"
const some_abstract_type &y = cx.get<some_abstract_type>();
用户定义的转换和模板“getter”都适用于 GCC。但是,英特尔 C++ 编译器在“getter”工作时似乎存在(用户定义的)转换问题。
例如,以下代码适用于 GCC,但不适用于 Intel:
#include <iostream>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
class container
{
public:
template<typename T> container(const boost::shared_ptr<T> &rhs)
: m_content(rhs) { }
template<typename T>
operator T const & () const
{
return get<T>();
}
template<typename T>
T const & get() const
{
return *boost::any_cast< boost::shared_ptr<T> >(m_content);
}
private:
boost::any m_content;
};
class base
{
public:
virtual ~base() { }
virtual void f() const = 0;
};
class derived : public base
{
public:
virtual ~derived() { }
virtual void f() const { std::cout << "hello\n"; }
};
void foo(const container &c)
{
const base & a = c;
a.f();
}
int main()
{
boost::shared_ptr<base> a(new derived);
container c = a;
foo(c);
}
使用 Intel,我收到此错误:
test.cpp(44): error: no suitable user-defined conversion from "const container" to "const base" exists
const base & a = c;
^
compilation aborted for test.cpp (code 2)
另一方面,如果我在main() 和foo() 中将base 替换为derived(或使用“getter”而不是foo() 中的类型转换),英特尔一切正常也。当T是抽象类时,是否可以说服Intel编译器使用用户定义的类型转换为引用类型?
提前感谢您的任何想法。
编辑:有趣的是,使用类型转换为指针类型可以正常工作。如果我添加
template<typename T>
operator T const * () const
{
return &get<T>();
}
到container 类并将foo() 替换为
void foo(const container &c)
{
const base * a = c;
a->f();
}
那么它也适用于英特尔。
【问题讨论】:
-
我对
**boost::any_cast< boost::shared_ptr<T> >(&m_content)而不是*boost::any_cast< boost::shared_ptr<T> >(m_content)的推理感到困惑(或者为什么m_content不只是一个boost::shared_ptr<T> >开始,但我猜测失去了原因因为那是由于您的简化);从源头来看,any_cast似乎确实支持any对象的传递引用(请参阅boost.any.hpp)。 -
@JAB 实际上
any_cast有两种变体,一种采用(常量/非常量)对any的引用并返回T(因此创建一个临时),另一种它接受一个指向any的指针并返回一个指向T的指针(随后可用于从函数返回对T的引用,因为它不会创建T的临时实例)。 -
在您提到的情况下,
T在技术上是shared_ptr<T>,并且由于您立即取消引用共享指针,因此除了尝试保存之外,您没有理由需要创建额外的指针一点点空间/CPU周期。 (大多数编译器无论如何都会忽略副本,因为shared_ptr<T>确实是在那个位置使用的临时对象,不是吗?除非您发现您使用的编译器在这种情况下不执行省略,使用指针form 似乎是一种不必要的抢先优化。) -
@JAB 我明白了,它实际上也有效。谢谢。编辑了问题。
-
在gcc.godbolt.org 上闲逛表明ICC will perform 转换为非常量参考。牺牲一点 const 正确性,你可能会有一个可行的解决方法。