使用static_cast实现的转换运算符

7

我在这里提出问题,是关于我在这里提出的问题。

问题很简单。假设你有两个这样的类:

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节和转换的第12.3节),但由于我的经验不足,我无法找出答案。非常感谢您花时间帮助我。

2
相关部分应该是重载决议的那一部分。 - R. Martinho Fernandes
如果您能满足我的好奇心——为什么您想要在“Base”中使用转换运算符? - Tony Delroy
1
@ Tony Delroy:1)比显式调用类方法更简洁。2)在尝试获取有关CRTP的知识时,我在网络上找到了这种代码几次,例如此处。3)发现这种奇怪的行为后,我真的很好奇哪个才是正确的 :-) - Massimiliano
2个回答

3

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

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

4/ 否则,如果声明T t(e);是良好形式的,就可以使用形式为static_cast<T>(e)static_cast将表达式e显式转换为类型T,其中t是一种虚构的临时变量[...]

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

static_cast<Derived const&>(*this)

不应递归调用 operator Derived const& () const。从“否则”关键字的存在可以推导出规则的顺序。规则2 / 应该在规则4 / 之前尝试。

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

外部代码调用class SomeImplfun1将被委托给class enable_crtp中适当的const或non-const版本的self(),并在向下转换实现do_fun1后进行调用。通过良好的编译器,所有间接引用应完全优化掉。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接