使用static_cast实现的转换运算符

Conversion operator implemented with static_cast

本文关键字:转换 运算符 实现 cast static 使用      更新时间:2023-10-16

在这里提出问题后,我提出了这个问题。

要点很简单。假设你有两个这样的类:

template < class Derived >
class Base {
...
operator const Derived&() const {
    return static_cast< const Derived& >(*this);
  }
...
};
class Specialization : public Base<Specialization> {
...
};

然后假设你有一个像这样的类型转换:

template < class T >
functionCall( const Base<T>& param) {
  const T & val(param);
  ...
}

问题是:这种转换的符合标准的行为应该是什么

它应该和const T & val(static_cast<const T &> (param) ) 一样,还是应该递归迭代直到堆栈溢出?请注意,我获得了使用GNU g++编译的第一个行为,以及使用Intel icpc编译的第二个行为。

我已经试着看一下这个标准(第5.9节关于static_cast,第12.3节关于转换),但由于缺乏经验,我无法找到答案。

我首先非常感谢任何花时间帮助我的人。

查看n3337中的[expr.static.cast](标准后的第一个工作草案):

2/如果存在从"指向D的指针"到"指向B的指针"的有效标准转换,则类型为"cv1 B"的左值(其中B是类类型)可以强制转换为类型"指向cv2 D的引用",其中D是从B派生的类(第10条)[…]

4/否则,对于某些发明的临时变量t[..],如果声明T t(e);格式良好,则表达式e可以使用形式为static_cast<T>(e)static_cast显式转换为类型T

因此,我认为gcc的行为是正确的,即表达式:

static_cast<Derived const&>(*this)

不应递归调用CCD_ 17。

我从Others关键字的存在推断出这一点,该关键字意味着规则的排序。规则2/应该在规则4/之前进行尝试。

不建议使用隐式转换运算符。在C++11中,您不仅可以将关键字explicit添加到单参数构造函数中,还可以添加到转换运算符中。对于C++03代码,可以使用显式命名的转换函数,如self()down_cast()

此外,您似乎正在为CRTP使用Base类,即启用静态多态性。这意味着您必须在编译时知道要调用哪个特定的Derived类。因此,除了实现CRTP接口之外,您不应该在任何公共代码中使用const Base&引用。

在我的项目中,我有一个类模板enable_crtp:

#include <type_traits>
#include <boost/static_assert.hpp>
template
<
        typename Derived
>
class enable_crtp
{
public:
        const Derived& self() const
        {
                return down_cast(*this);
        }
        Derived& self()
        {
                return down_cast(*this);
        }
protected:
        // disable deletion of Derived* through Base* 
        // enable deletion of Base* through Derived*
        ~enable_crtp()
        {
                // no-op
        }
private:
        // typedefs
        typedef enable_crtp Base;
        // cast a Base& to a Derived& (i.e. "down" the class hierarchy)
        const Derived& down_cast(const Base& other) const
        {
              BOOST_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
              return static_cast<const Derived&>(other);
        }
        // cast a Base& to a Derived& (i.e. "down" the class hierarchy)
        Derived& down_cast(Base& other)
        {
        // write the non-const version in terms of the const version
        // Effective C++ 3rd ed., Item 3 (p. 24-25)
        return const_cast<Derived&>(down_cast(static_cast<const Base&>(other)));
        }
};

这个类是由任何CRTP基类ISomeClass私有派生的,如下所示:

template<typename Impl>
class ISomeClass
:
    private enable_crtp<Impl>
{
public:
    // interface to be implemented by derived class Impl
    void fun1() const
    {
        self().do_fun1();
    }
    void fun2()
    {
        self().do_fun2()
    }
protected:
    ~ISomeClass()
    {}  
};

各种派生类可以用它们自己的特定方式实现这个接口,比如:

class SomeImpl
:
    public ISomeClass<SomeImpl>
{
public:
    // structors etc.
private:
    // implementation of interface ISomeClass
    friend class ISomeClass<SomeImpl>;
    void do_fun1() const
    {
        // whatever
    }
    void do_fun2() 
    {
        // whatever
    }
    // data representation
    // ...
};

调用class SomeImplfun1的外部代码将被委托给class enable_crtp中的self()的适当常量或非常量版本,并且在down_cast之后将调用实现do_fun1。有了一个不错的编译器,所有的间接寻址都应该完全优化掉。

注意:受保护的ISomeClassenable_crtp的析构函数使代码对试图通过基指针删除SomeImpl*对象的用户是安全的。