这里首先是一个简单的示例,以更好地解释我的意思。
template <typename T>
class TemplateClass
{
public:
void print();
};
template <>
void TemplateClass<int>::print()
{
std::cout << "T is an int!" << std::endl;
}
template <>
void TemplateClass<float>::print()
{
std::cout << "T is a float!" << std::endl;
}
int main()
{
TemplateClass<int> i;
i.print();
TemplateClass<float> f;
f.print();
system("PAUSE");
}
在此,我根据T是int还是float来覆盖print()函数。
程序打印:
T is an int!
T is a float!
Press any key to continue . . .
我真正想要做的是基于派生自哪个类T的此类覆盖,可以从中派生T的类是其他模板类,因为它们使用了好奇的递归模板模式。
这是我尝试过的,我想不出其他任何方式
template <typename T>
class BaseOne {};
template <typename T>
class BaseTwo {};
struct DerivedOne : public BaseOne<DerivedOne>
{
int i;
};
struct DerivedTwo : public BaseTwo<DerivedTwo>
{
float x, y, z;
};
template <typename T>
class TemplateClass
{
public:
void print();
};
template <typename U>
void TemplateClass<BaseOne<U>>::print()
{
std::cout << "U is derived from BaseOne!" << std::endl;
}
template <typename U>
void TemplateClass<BaseTwo<U>>::print()
{
std::cout << "U is derived from BaseTwo!" << std::endl;
}
int main()
{
TemplateClass<DerivedOne> d1;
d1.print();
TemplateClass<DerivedTwo> d2;
d2.print();
system("PAUSE");
}
程序应打印:
U is derived from BaseOne!
U is derived from BaseTwo!
Press any key to continue . . .
但是我却得到了错误
// I believe this is the main error
Error (active) E0498 template argument list must match the parameter list
// And these errors comes as a result of the error above
Error C2039 'print': is not a member of 'TemplateClass<BaseOne/BaseTwo<T>>'
// BaseOne/BaseTwo on respective lines in code
Error C2447 '{': missing function header (old-style formal list?)
在线
void TemplateClass<BaseOne<U>>::print()
and
void TemplateClass<BaseTwo<U>>::print()
我有点迷路,不胜感激!
答案 0 :(得分:4)
有一个for key, values in d.items():
类型的特征。
is_base_of
。
此外,std::is_base_of_v<BaseOne<T>, T>
将永远不会在static_assert(false)
和GCC
上进行编译。使条件取决于类型参数将起作用。
Clang
顺便说一句,您真的需要static_assert(sizeof(T) < 0)
吗?您可以在C ++ 17中使用if constexpr:
overriding/specialization
如果您确实需要覆盖/专业化,请使用template <typename T>
void TemplateClass<T>::print() {
if constexpr (std::is_convertible_v <TemplateClass<T>*, BaseOne*>)
std::cout << "U is derived from BaseOne!" << std::endl
} else if (std::is_convertible_v <TemplateClass<T>*, BaseTwo*>) {
std::cout << "U is derived from BaseTwo!" << std::endl;
} else {
static_assert(false); // add error
}
}
(SFINAE)
答案 1 :(得分:0)
您可以对课程进行部分专业化,但必须对整个课程进行部分专业化。您正在尝试仅对课程的 part 部分进行专业化。
像这样的事情会有效
template <typename T>
class TemplateClass<BaseOne<T>>
{
public:
void print()
{
std::cout << "U is derived from BaseOne!" << std::endl;
}
};
由于TemplateClass<DerivedOne>
与TemplateClass<BaseOne<DerivedOne>>
不同,因此代码仍然无法正常工作。完全专业化和部分专业化匹配确切的类型,并且不考虑继承。
使用Ben所建议的类型特征。
答案 2 :(得分:0)
您不能部分专门化方法/功能。
您可以像int
/ float
那样完全专精。
我建议标签分发,因为您可以轻松添加新的(模板化)重载:
template <typename> struct Tag {};
template <typename T>
class TemplateClass
{
public:
auto print() -> decltype(helper_print(tag<T>{});) // SFINAE friendly
// void print() // Simple, but SFINAE unfriendly
{ return helper_print(tag<T>{}); }
};
然后,您之前的代码将是:
void helper_print(Tag<int>)
{
std::cout << "T is an int!" << std::endl;
}
void helper_print(Tag<float>)
{
std::cout << "T is a float!" << std::endl;
}
您甚至可以添加模板化标签:
template <typename U>
void helper_print(Tag<std::vector<U>>)
{
std::cout << "T is a std::vector!" << std::endl;
}
第二部分,因为您需要SFINAE和特征,所以比较棘手:
// Create traits
template <template <typename> class C, typename U>
std::true_type HasTemplateBaseImpl(C<U>*);
template <template <typename> class C>
std::false_type HasTemplateBaseImpl(...);
template <typename T, template <typename> class C>
using has_template_base = decltype(HasTemplateBaseImpl<C>(std::declval<T*>()));
然后
template <typename T,
std::enable_if_t<has_template_base<T, BaseOne>::value, bool> = false>
void helper_print(Tag<T>)
{
std::cout << "T is derived from BaseOne!" << std::endl;
}
template <typename T,
std::enable_if_t<has_template_base<T, BaseTwo>::value, bool> = false>
void helper_print(Tag<T>)
{
std::cout << "T is derived from BaseTwo!" << std::endl;
}