是否可以从传递到另一个模板的模板中获取typename?以下是目标的基本示例
#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>'
,因为根本没有在Observable中使用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的基础,它应该有一个类型定义。
答案 0 :(得分:1)
在您的情况下,由于您在Object
类中定义了typedef,因此您可以这样做:
template <typename T>
class Observable<T, typename std::enable_if<std::is_base_of<Object<typename T::T>, T>::value>::type>
如果你没有使用那个typedef,你可以这样做:
// 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
上。如果使用get_object_type
无法调用函数const T&
,则将排除Observable
的特化。如果T
没有延伸Object<T>
,但功能get_object_type
仍然可以调用,那么is_base_of
的条件将排除Observable
的专业化