使用static_cast实现转换运算符

时间:2012-03-22 09:17:55

标签: c++ standards crtp static-cast conversion-operator

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

重点非常简单。假设您有两类此类:

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++进行编译的第一个行为,以及使用英特尔icpc进行第二次编译。

我已经试图查看标准(关于static_cast的第5.9节和关于转换的第12.3节),但由于我缺乏经验,我无法找到答案。

我非常感谢任何花时间帮助我解决这个问题的人。

2 个答案:

答案 0 :(得分:3)

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

  

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

     

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

,声明t格式正确

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

static_cast<Derived const&>(*this)

不应递归调用operator Derived const& () const

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

答案 1 :(得分:0)

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

此外,您似乎使用Base类进行CRTP,即启用静态多态。这意味着您必须在编译时知道您正在调用的特定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
    // ...
};

fun1的外部代码调用class SomeImpl将被委派给self()class enable_crtp的{​​{1}}的相应const或非const版本,并且在向下传播实现{{1}之后将被调用。使用合适的编译器,所有的间接都应该完全优化。

注意:do_fun1ISomeClass的受保护析构函数可以使代码对尝试通过基本指针删除enable_crtp个对象的用户安全。