带有基类的模板类

时间:2014-03-21 09:02:29

标签: c++ templates metaprogramming derived

如何为整个基类专门化一个类?所以我有

template <bool b>
struct selector
{
};
template <typename T1, typename T2>
struct typeequal : selector<false>
{
};
template <typename T>
struct typeequal<T, T> : selector<true>
{
};

不,我想创建专门的类,一个用于T1 = T2,一个用于T1!= T2。我用

试了一下
template <typename T>
class myClass;

template <>
class myClass<selector<true> >
{
    // ...
}
template <>
class myClass<selector<false> >
{
    // ...
}

然后我尝试用

调用它
myClass<typeequal<int, int> > x;

哪个不起作用。我认为,问题是,在检查哪个模板匹配时没有转换。但是如何解决?

5 个答案:

答案 0 :(得分:1)

专业化系统不考虑基类。不过,您仍然可以找到具有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 >
{
    // ...
};

答案 1 :(得分:0)

如果您的目标是创建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( "%d\n", x1.types_equal );
    printf( "%d\n", x2.types_equal );
}

答案 2 :(得分:0)

哦,好吧,我明白你的意思了。

所以C ++元编程的问题在于你只能将这些东西作为模板参数传递:

  • 类型参数。
    • 类型
    • 模板(仅限课程,无功能)
  • 非类型参数
    • 指针
    • 参考
    • 积分常量表达式

因此,您必须能够仅使用非常有限的信息进行交流,这就是为什么某些模板看起来像一个含有许多成分的意大利面条的原因。你必须有时使用:: value或:: type字段(它成为某种标准),以传递一些模仿一个值的东西,并带来一些信息,你可以用它来进一步评估模板,这样你就可以使用了不同的技巧和技术,但最后它们看起来像很多不同的插件,而不是干净和可读的实现。这就是为什么有些人发明了type_traits,它假设有助于简化某些类型的操作,比如is_base_of - 它允许你检查A类是否是从B派生的,但如果要在某些模板中使用,则必须再次检查:: value 。

PS。 type_trait能力之一是检查类型是否为整数is_integral,以便在需要检查是否使用纯bool时可以使用它。您还可以在模板参数中传递此信息作为bool类型的测试。

答案 3 :(得分:0)

正如@Potatowater所说,专业化系统不考虑基础契约(A类型只是一种类型,类型系统上没有协方差/逆变)。

另一方面,解决问题的最简单方法是使用布尔参数而不是类型:

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;

答案 4 :(得分:0)

如您所料,模板不会隐式处理专门化机制中的继承。但是,您可以明确管理它。这是一个例子:

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