C++ 在编译时使用模板选择要调用的函数

C++ 在编译时使用模板选择要调用的函数,c++,c++11,templates,template-specialization,C++,C++11,Templates,Template Specialization,我正在使用C++11,并试图在我的应用程序中设置一个通用的Handle类,在这个类中,有时可以转换具有不同底层类型的句柄,但前提是底层类型与祖先/后代相关,否则转换的尝试就会失败。我还需要一个永远不会失败的函数,它告诉我这两种类型之间是否可以进行转换。特别是,我不希望基础类型尝试对不在其自身祖先/后代行内的类型进行任何转换,因此我想如果我在布尔值上定义了一个模板函子,在编译时告诉我这些类型是否相关,并使用模板专门化拒绝不相关的转换,或者将转换请求转发到基础类型(如果它们相关)。每个基类都包含一个

我正在使用C++11,并试图在我的应用程序中设置一个通用的
Handle
类,在这个类中,有时可以转换具有不同底层类型的句柄,但前提是底层类型与祖先/后代相关,否则转换的尝试就会失败。我还需要一个永远不会失败的函数,它告诉我这两种类型之间是否可以进行转换。特别是,我不希望基础类型尝试对不在其自身祖先/后代行内的类型进行任何转换,因此我想如果我在布尔值上定义了一个模板函子,在编译时告诉我这些类型是否相关,并使用模板专门化拒绝不相关的转换,或者将转换请求转发到基础类型(如果它们相关)。每个基类都包含一个模板转换函数,该函数知道如何转换为it层次结构中的每个相应类型,还包含一个模板布尔函数,该函数根据类实例的内部状态指示是否可以进行此类转换

我把它们放在一起,看起来像这样:

template<class T>
class MyHandle {
public:
    ...
    template<bool> struct can_be_ref {    
        template<class U> bool operator()(const MyHandle *, const U*) const
        {
        }
    };

    template<bool> struct as_ref {
        template<class U> MyHandle<U> operator()(const MyHandle *, const U*) const
        {
            throw std::runtime_error("Illegal type conversion");
        }
    };
    template<class U> bool can_be();
    template<class U> MyHandle<U> as();
private:
    const T* get_member_reference() const;
};

template<class T> struct MyHandle<T>::can_be_ref<true> {    
    template<class U> bool operator()(const MyHandle<T> *ptr, const U*)
    {
        ptr->get_member_reference()->can_be<U>();
    }
};

template<class T> struct MyHandle<T>::as_ref<true> {    
    template<class U> MyHandle<U> operator()(const MyHandle<T> *ptr, const U*) const
    {
        return ptr->get_member_reference()->as<U>();
    }
};

template<class T> template<class U> bool MyHandle<T>::can_be()
{
    return can_be_ref < std::is_base_of<T, U>::value || std::is_base_of<U, T>::value > ()(this, reinterpret_cast<const U *> (nullptr));
}

template<class T> template<class U> MyHandle<U> MyHandle<T>::as()
{
    return as_ref < std::is_base_of<T, U>::value || std::is_base_of<U, T>::value > ()(this, reinterpret_cast<const U *> (nullptr));
}
每个层次结构都定义了一个
可以
as
方法,该方法只涉及其层次结构中的项,特别是在某些情况下,如果模板的参数类型不正确,则可能导致编译器错误,这就是为什么必须在编译时检查该类型。
假设我们定义了以下变量:

MyHandle<A> a;
MyHandle<B> b;
MyHandle<C> c;
我决定放弃对无效转换抛出异常,现在MyHandle的每个实例都包含一个名为
value
的空指针,它可以包含一个指针,指向有关实际底层类型的更多信息,如果无效,则为null ptr,然后我可以为MyHandleConverterClass创建一个部分专门化,如下所示:

template<class T,class U,bool> class MyHandleConverter
{
public:
    inline MyHandleConverter(const MyHandle<T> *) { }
    inline bool can_be() const { return false; }
    inline MyHandle<U> as() const { return MyHandle<U>(nullptr); }
};
template<class T,class U> class MyHandleConverter<T,U,true> {
public:
    inline MyHandleConverter(const MyHandle<T> *ref):reference(ref) { }    
    inline bool can_be() const {
        if (std::is_base_of<T,U>::value) {
            return true;
        } else if (reference->value == nullptr) {
            return false;
        } else {
            return reference->underlying_can_be((const U*)(nullptr));
        }
    }
    inline MyHandle<U> as() const { 
        if (std::is_base_of<U,T>::value) {
            return MyHandle<U>(reference->value);
        } else if (reference->value == nullptr) {
            return MyHandle<U>(nullptr);
        } else {
            return reference->underlying_as((const U*)(nullptr)); 
        }
    }
private:
    const MyHandle<T> *reference;    
};
其中
are\u handle\u types\u related
是一个模板化的constexpr函数,如果发现调用底层模板化类型的关系非常密切,那么为MyHandle的
方法调用底层类型不会导致编译器错误,则返回true,或者,在某些情况下,如果不在每个底层类型
as
中编写复杂的检测逻辑,在编译时甚至在运行时都无法检测到的逻辑错误可以是
方法,只需检测到这两个类都是从适当的类型派生出来的,以便转换过程合理地成功即可


这样,当由
检测到的类型不兼容时,如果类型与
相关,则调用相应类型的
can\u be
as
方法是无效的,创建的
MyHandleConverter
实例是
MyHandleConverter
,它不尝试调用底层类类型,而
MyHandleConverter
则尝试调用底层类类型,但将仅针对已经发现可以通过任何方式调用基础类型的适当对话函数的类进行实例化。

要专门化模板,您必须在专门化之前添加
模板
关键字,如:

template<class T> // Template parameter for 'MyHandle<T>'
template<> // No unspecialized template parameters for 'can_be_ref', but indicate that it is a template anyway
struct MyHandle<T>::can_be_ref<true> 
{    
    template<class U> bool operator()(const MyHandle<T> *ptr, const U*)
    {
        ptr->get_member_reference()->can_be<U>();
    }
};
然后我们可以进行部分专业化:

template<class T>
template<class U>
struct MyHandle<T>::can_be_ref<U, true>
{
    bool operator()(const MyHandle<T> * ptr, const U*) const
    {
        return ptr->get_member_reference()->can_be<U>();
    }
};

template<class T>
template<class U>
struct MyHandle<T>::as_ref<U, true>
{
    MyHandle<U> operator()(const MyHandle<T> *ptr, const U*) const
    {
        return ptr->get_member_reference()->as<U>();
    }
};

template<class T>
template<class U> bool MyHandle<T>::can_be() const
{
    return can_be_ref<U,
            std::is_base_of<T, U>::value || std::is_base_of<U, T>::value>()(
            this, nullptr);
}

template<class T>
template<class U> MyHandle<U> MyHandle<T>::as()
{
    return as_ref<U,
            std::is_base_of<T, U>::value || std::is_base_of<U, T>::value>()(
            this, nullptr);
}

我不清楚你希望如何使用它们。什么是有效的用法?什么是无效用法?发布它们将非常有用。
template<class T> // Template parameter for 'MyHandle<T>'
template<> // No unspecialized template parameters for 'can_be_ref', but indicate that it is a template anyway
struct MyHandle<T>::can_be_ref<true> 
{    
    template<class U> bool operator()(const MyHandle<T> *ptr, const U*)
    {
        ptr->get_member_reference()->can_be<U>();
    }
};
template<class T>
class MyHandle
{
public:
...
    template<class U, bool>
    struct can_be_ref
    {
        bool operator()(const MyHandle<T> *ptr, const U*) const
        {
            return false;
        }
    };

    template<class U, bool>
    struct as_ref
    {
        MyHandle<U> operator()(const MyHandle<T> *, const U*) const
        {
            throw std::runtime_error("Illegal type conversion");
        }
    };
...
};
template<class T>
template<class U>
struct MyHandle<T>::can_be_ref<U, true>
{
    bool operator()(const MyHandle<T> * ptr, const U*) const
    {
        return ptr->get_member_reference()->can_be<U>();
    }
};

template<class T>
template<class U>
struct MyHandle<T>::as_ref<U, true>
{
    MyHandle<U> operator()(const MyHandle<T> *ptr, const U*) const
    {
        return ptr->get_member_reference()->as<U>();
    }
};

template<class T>
template<class U> bool MyHandle<T>::can_be() const
{
    return can_be_ref<U,
            std::is_base_of<T, U>::value || std::is_base_of<U, T>::value>()(
            this, nullptr);
}

template<class T>
template<class U> MyHandle<U> MyHandle<T>::as()
{
    return as_ref<U,
            std::is_base_of<T, U>::value || std::is_base_of<U, T>::value>()(
            this, nullptr);
}
class A {
public:
  template<class U> bool can_be(const U*)
{
return can_be<U>();
}
  template<class U> MyHandle<U> as(const U*)
{
return as<U>();
}

  template<class U> bool can_be();
  template<class U> MyHandle<U> as();
};

template<class T>
    template<class U>
    struct MyHandle<T>::can_be_ref<U, true>
    {
        bool operator()(const MyHandle<T> * ptr, const U* uptr) const
        {
            return ptr->get_member_reference()->can_be(uptr);
        }
    };

    template<class T>
    template<class U>
    struct MyHandle<T>::as_ref<U, true>
    {
        MyHandle<U> operator()(const MyHandle<T> *ptr, const U* uptr) const
        {
            return ptr->get_member_reference()->as(uptr);
        }
    };