2012-03-22 128 views
7

我在问题提出here后问这个问题。用static_cast实现的转换运算符

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

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

相关部分将是重载解析的部分。 – 2012-03-22 09:23:36

+0

如果你幽默我的好奇心 - 你为什么要在'基地'的转换运算符? – 2012-03-22 09:43:24

+1

@ Tony Delroy:1)比明确调用一个类方法更简洁.2)在尝试获取关于CRTPs的一些知识时,我在网络中偶尔发现了这种代码,参见[here](http ://en.wikipedia.org/wiki/Expression_templates)3)发现这种奇怪的行为后,我真的很好奇哪一个应该是正确的:-) – Massimiliano 2012-03-22 09:57:19

回答

3

综观[expr.static.cast]n3337(标准后第一工作草案):

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

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

因此,我想解释的是海湾合作委员会的行为是正确的,即表达:

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

外部代码fun1class SomeImpl将被授权给class enable_crtp中的self()的适当const或非const版本,并且在down_casting之后将调用实现do_fun1。用一个体面的编译器,所有的indirections应该完全被优化。

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