带有基类的模板类

template class with a base class

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

如何为整个基类专门化一个类?这里是

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>>来定义每种情况下的功能。