从模板中通过通过

Get typename from passed in template

本文关键字:      更新时间:2023-10-16

是否有可能将输入键从传递到另一个模板中的模板中?这是目标的基本示例

#include <memory>
#include <string>
#include <iostream>
class IntId {
private:
    int id;
public:
    IntId(int id) {
        this->id = id;
    }
};
class StringId {
private:
    std::string id;
public:
    StringId(std::string id) {
        this->id = id;
    }
};
template<typename T_Id>
class Object : public std::enable_shared_from_this<Object<T_Id>>
{
private:
    T_Id id;
public:
    typedef T_Id T;
    Object(T_Id id) {
        this->id = id;
    }
    T_Id getId()
    {
        return this->id;
    }
};

template <class T, class Enable = void>
class Observable {
public:
    // Intentionally doesn't have a set so it breaks the build... I want both types to go into the value below
    void setNonSpecialized(T value) {
    }
};
template<typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<IntId>, T>::value>::type> {
    private:
        std::shared_ptr<T> value;
    public:
        Observable() {
            value = nullptr;
        };
        void set(std::shared_ptr<T> newValue) {
            this->value = newValue;
        }
};
class UPCObject : public Object<IntId> {
};
class UserObject : public Object<StringId> {
};

int main()
{
    auto upcObject = std::make_shared<UPCObject>();
    auto upcObservable = std::make_shared<Observable<UPCObject>>();
    upcObservable->set(upcObject); // Expected to succeed as UPCObject inherits from Object<IntId> which matches template
    auto userObject = std::make_shared<UserObject>();
    auto userObservable = std::make_shared<Observable<UserObject>>();
    userObservable->set(userObject); // Want this to succeed as UserObject inherits from Object<StringId> which would match template Object<T::T_Id>
    auto intObservable = std::make_shared<Observable<int>>();
    intObservable->setNonSpecialized(0); // Expected to succeed and use the value on non-specialized Observable
    return 0;
}

在上面的代码中,upcobject在其构建中取得了成功,因为它的类型与模板类型匹配。userObject不是因为它具有不同的ID类型。

现在,如果我将专业化更改为以下并明确描述类型

template <typename T, typename T_Id>
class Observable<T, typename std::enable_if<std::is_base_of<Object<T_Id>, T>::value>::type>

我得到构建错误'T_Id': template parameter not used or deducible in partial specialization 'Observable<T,std::enable_if<std::is_base_of<Object<T_Id>,T>::value,void>::type>',因为T_ID实际上根本没有使用。

如果我能做以下

之类的事情,那就太好了
template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<T::T_Id>, T>::value>::type>

我能够从所传递的类型中获取T_ID。因为在此专业化中,我要检查对象的基础,因此它应该在其上定义了类型。

在您的情况下,由于您在 Object类中定义了typedef,因此您可以简单地执行此操作:

template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<typename T::T>, T>::value>::type>

如果您不使用该类型,可以这样做:

// returning a pointer protect us from abstract types.
template<typename T>
T* get_object_type(const Object<T>&);
template<typename T>
using object_type_t = typename std::remove_pointer<
    decltype(get_object_type(std::declval<const T&>()))
>::type;

然后使用类型特征:

template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<object_type_t<T>, T>::value>::type>

请注意,Sfinae将首先在object_type_t上发生。如果使用const T&无法调用该功能get_object_type,则将排除Observable的专业化。如果T不扩展Object<T>,但是函数get_object_type仍然可召唤,则使用is_base_of的条件将排除Observable的专业化。

相关文章:
  • 没有找到相关文章