带有基类的模板类
template class with a base class
如何为整个基类专门化一个类?这里是
template <bool b>
struct selector
{
};
template <typename T1, typename T2>
struct typeequal : selector<false>
{
};
template <typename T>
struct typeequal<T, T> : selector<true>
{
};
不,我想创建两个专门的类,一个用于if T1 = T2,一个用于if T1 != T2。我试过
template <typename T>
class myClass;
template <>
class myClass<selector<true> >
{
// ...
}
template <>
class myClass<selector<false> >
{
// ...
}
然后我试着用
调用它myClass<typeequal<int, int> > x;
不起作用。我认为,问题是,没有转换,当检查哪个模板匹配。但是如何修复呢?
特化系统不考虑基类。但是,您仍然可以找到具有SFINAE自省和部分专门化的基础。
template <typename T, typename = void >
class myClass;
template <typename T>
class myClass<T,
typename std::enable_if<
std::is_same<
typename T::selector, // If member "selector"
selector<true> // is the class, assume it's derived
>::value
> ::type >
{
// ...
};
template <typename T>
class myClass<T,
typename std::enable_if< std::is_same< typename T::selector, selector<false> >::value
> ::type >
{
// ...
};
哦,我明白你的意思了。
所以c++元编程的问题是你只能把这些东西作为模板参数传递:
- 类型参数。
- 模板(只有类,没有函数)
- 实参数
- <
- 指针/gh>引用
- 整型常量表达式
所以你必须能够只使用非常有限的信息进行交流,这就是为什么一些模板看起来像含有许多成分的意大利面。有时你必须使用::value或::type字段(它成为某种标准)来传递一些可以模拟值的东西,并带来可以在模板的进一步评估中使用的信息,因此你可以使用不同的技巧和技术来完成它,但最终它们看起来像许多不同的插件,而不是干净可读的实现。这就是为什么有些人发明了type_traits,它可以帮助简化一些类型的操作,比如is_base_of——它允许你检查类A是否派生自类B,但如果你想在某些模板中使用::值,你必须再次检查。
p。type_trait的功能之一是检查类型是否为整型(is_integral),因此如果需要检查是否使用了纯bool类型,就可以使用它。您还可以将此信息作为模板参数中bool类型的测试来传递。
如果您的目标是创建myClass的专门版本-您可以尝试更明智的类型方法,如:
struct True{};
struct False{};
template < typename T1, typename T2 >
struct typeequal
{
typedef False value;
};
template < typename T >
struct typeequal< T, T >
{
typedef True value;
};
template < typename T >
class myClass;
template<>
class myClass< True >
{
enum{ types_equal = true };
};
template<>
class myClass< False >
{
enum{ types_equal = false };
};
int main()
{
myClass< typeequal< int, int >::value > x;
}
如果你真的想在那里继承,你可以尝试使用True和False作为基类,但我不认为有什么理由这样做,除非你有别的想法。
希望对你有帮助:)
编辑:
在这种情况下,你可以这样做:
#include <stdio.h>
template< bool b >
struct selector {};
template < typename T1, typename T2 >
struct typeequal : selector< false > { };
template < typename T >
struct typeequal< T, T > : selector< true > { };
template < typename T >
class myClass;
template< typename T1, typename T2 >
class myClass< typeequal< T1, T2 > >
{
public:
enum{ types_equal = false };
};
template< typename T >
class myClass< typeequal< T, T > >
{
public:
enum{ types_equal = true };
};
int main()
{
myClass< typeequal< int, int > > x1;
myClass< typeequal< int, char > > x2;
printf( "%dn", x1.types_equal );
printf( "%dn", x2.types_equal );
}
正如@Potatowater所说,特化系统不考虑基类(类型只是一个类型,类型系统上没有协方差/逆变)。
另一方面,解决这个问题最简单的方法就是使用布尔参数而不是类型:template<bool VALUE>
struct boolean_constant
{
static const bool value = VALUE;
};
typedef boolean_constant<true> true_type;
typedef boolean_constant<false> false_type;
template<typename T , typename U>
struct is_same : public boolean_constant<false> {};
template<typename T>
struct is_same<T,T> : public boolean_constant<true> {};
template<bool CONDITION>
struct myClass
{
...
};
template<>
struct myClass<false>
{
...
};
myClass<is_same<int,int>::value> foo;
如果您可以访问c++ 11,您的目标可以直接使用模板别名实现。考虑:
template<typename RESULT>
struct function
{
typedef RESULT result;
};
这是一个元函数,用来表示一个函数,即通过result
别名计算并返回结果的东西。
现在你实现你的元函数使用它作为基础:
template<typename T , typename U>
struct is_same_impl : public function<boolean_constant<false>> {};
template<typename T>
struct is_same_impl<T,T> : public function<boolean_constant<true>> {};
现在您提供给用户的函数只是对实现结果的别名:
template<typename T , typename U>
using is_same = typename is_same_impl<T,U>::result;
使用它,你可以用你一直在尝试的方式专门化你的类:
template<typename T>
struct myClass;
template<>
struct myClass<true_type>
{
...
};
template<>
struct myClass<false_type>
{
...
};
myClass<is_same<int,int>> foo;
正如您所怀疑的,模板并不隐式地处理专门化机制中的继承。但是,您可以显式地管理它。下面是一个例子:
#include <iostream>
#include <utility>
template <bool b>
struct selector
{
};
template <typename T1, typename T2>
struct typeequal : selector<false>
{
};
template <typename T>
struct typeequal<T, T> : selector<true>
{
};
template <bool b>
selector<b> as_selector(selector<b> *);
template <typename T>
struct myClass : myClass<decltype(as_selector((T*)nullptr))> {
};
template <>
struct myClass<selector<true> >
{
bool value() { return true; }
};
template <>
struct myClass<selector<false> >
{
bool value() { return false; }
};
int main()
{
myClass<typeequal<int,int> > x;
myClass<typeequal<int,float> > y;
std::cout << x.value() << "n";
std::cout << y.value() << "n";
}
输出1和0。
这里的技巧是使用函数模板显式地将模板参数T
转换为适当的selector<b>
基类,这确实处理继承。我们首先定义一个函数,它可以接受指向selector<b>
(或从它派生的任何东西)的指针,并让它返回匹配的选择器类型:
template <bool b>
selector<b> as_selector(selector<b> *);
接下来,使用decltype
返回函数将返回的类型;只要传递一个空指针给T
,我们就可以从它派生出一般的myClass
:
template <typename T>
struct myClass : myClass<decltype(as_selector((T*)nullptr))> {
};
现在,由于myClass<type_equal<A,B>>
派生自selector<b>
,我们可以专门化myClass<selector<b>>
来定义每种情况下的功能。
- std::具有相同基类的类的变体
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 基类中的函数名称解析
- C++初始化基类
- 如何通过派生类函数更改基类中的向量
- 如何定义一个纯抽象基类
- 如何使用基类指针引用派生类成员
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 如果基类包含双指针成员,则派生类的构造函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 为什么此派生对象无法访问基类的后递减方法?
- 公开最直接的基类模板名称
- 当基类是依赖类型时,这是一个缺陷吗
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 模板基类中的静态变量
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 继承和友元函数,从基类访问受保护的成员