复杂的C ++模板代码

时间:2017-01-20 13:37:32

标签: c++ templates

我一直致力于为C#开放C ++的opencascade C ++包装器。 我的C ++有点生疏,因为我过去几年主要使用C#。

现在我遇到了以下问题,但无法弄清楚如何纠正它:

size >=2

compilor错误如下:

#include <type_traits>

//! Trait yielding true if class T1 is base of T2 but not the same
template <class T1, class T2, class Dummy = void>
struct is_base_but_not_same : std::is_base_of <T1, T2> {};

//! Explicit specialization of is_base_of trait to workaround the
//! requirement of type to be complete when T1 and T2 are the same.
template <class T1, class T2>
struct is_base_but_not_same <T1, T2, typename std::enable_if <std::is_same <T1, T2>::value>::type> : std::false_type {};

template <class T>
class handle
{
public:
    //! Down casting operator from handle to base type
    template <class T2>
    static typename std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
        DownCast(const handle<T2>& theObject)
    {
        return handle(dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
    }

    //! Down casting operator from pointer to base type
    template <class T2>
    static typename std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
        DownCast(const T2* thePtr)
    {
        return handle(dynamic_cast<T*>(const_cast<T2*>(thePtr)));
    }
};

class Foo
{

};

typedef handle<Foo> Handle_Foo;

Handle_Foo DownCastFoo(Handle_Foo const &T) {
    return Handle_Foo::DownCast(T);
}

有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:2)

提供的示例中有多个错误。

首先,该示例意味着T*类的get()构造函数和handle方法。将这些添加到handle类:

explicit handle(T*);
const T* get() const;

其次,你正试图从handle<Foo>handle<Foo>投降,这是一种毫无意义的操作。 Foo甚至不是多态的。你的向下转换方法似乎专门设计为不提供这种重载,因此你得到的错误。将Foo定义为多态并添加派生类Bar

struct Foo { virtual ~Foo() = default; };
struct Bar : public Foo {};

最后,更改DownCastFoo以尝试向下转换为Bar而不是Foo,并且错误已得到解决。

typedef handle<Foo> Handle_Foo;
typedef handle<Bar> Handle_Bar;

Handle_Bar DownCastFoo(Handle_Foo const &T) {
    return Handle_Bar::DownCast(T);
}

作为最后一点,那些const_cast看起来非常可疑。遗憾的是,您的示例中没有足够的信息来提供更好的建议。

完整正确的例子

#include <type_traits>

//! Trait yielding true if class T1 is base of T2 but not the same
template <class T1, class T2, class Dummy = void>
struct is_base_but_not_same : std::is_base_of <T1, T2> {};

//! Explicit specialization of is_base_of trait to workaround the
//! requirement of type to be complete when T1 and T2 are the same.
template <class T1, class T2>
struct is_base_but_not_same <T1, T2, typename std::enable_if <std::is_same <T1, T2>::value>::type> : std::false_type {};

template <class T>
class handle
{
public:
    explicit handle(T*);
    const T* get() const;
public:
    //! Down casting operator from handle to base type
    template <class T2>
    static typename std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
        DownCast(const handle<T2>& theObject)
    {
        return handle(dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
    }

    //! Down casting operator from pointer to base type
    template <class T2>
    static typename std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
        DownCast(const T2* thePtr)
    {
        return handle(dynamic_cast<T*>(const_cast<T2*>(thePtr)));
    }
};

struct Foo { virtual ~Foo() = default; };
struct Bar : public Foo {};

typedef handle<Foo> Handle_Foo;
typedef handle<Bar> Handle_Bar;

Handle_Bar DownCastFoo(Handle_Foo const &T) {
    return Handle_Bar::DownCast(T);
}

编辑:看起来enable_if仅用于避免非法重载。如果您使用static_assert,则会得到更好的编译错误。

使用static_assert的示例:

template <class T>
class handle
{
public:
    explicit handle(T*);
    const T* get() const;
public:
    //! Down casting operator from handle to base type
    template <class T2>
    static handle DownCast(const handle<T2>& theObject)
    {
        static_assert(std::is_same<T, T2>::value == false,
            "Can't downcast from between identical types");
        static_assert(std::is_base_of<T2, T>::value, 
            "Can only down cast from a derived type to a base type");
        return handle(dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
    }

    //! Down casting operator from pointer to base type
    template <class T2>
    static handle DownCast(const T2* thePtr)
    {
        static_assert(std::is_same<T, T2>::value == false,
            "Can't downcast from between identical types");
        static_assert(std::is_base_of<T2, T>::value, 
            "Can only down cast from a derived type to a base type");
        return handle(dynamic_cast<T*>(const_cast<T2*>(thePtr)));
    }
};

现在,您的原始用例将生成错误消息"Can't downcast from between identical types"

struct Foo { virtual ~Foo() = default; };
struct Bar : public Foo {};

typedef handle<Foo> Handle_Foo;

Handle_Foo DownCastFoo(Handle_Foo const &T) {
    return Handle_Foo::DownCast(T);
}