用部分实例化的祖先类替换完全实例化的类

时间:2013-04-01 09:06:37

标签: c++ templates inheritance instantiation sfinae

当我在表单中提供模板参数时,我希望accepted_dense_vector<??>::value返回'true'

C<T>C时,{p> uvectordynamic_arrayTstd::is_arithmetic

std::array<T,S>T

std::is_arithmetic

container_reference<C>为'true'时

accepted_dense_vector<C>::value

一切正常,但在派生的,完全实例化的类A,C,D中,我想删除变通方法parent定义。

我该怎么做?

#include <iostream>
#include <array>
using namespace std;

// Definition of used types.
template<typename T> struct dynamic_array {};
template<typename T> struct uvector {};
struct A : public uvector<double> { typedef uvector<double> parent; };
struct C : public A { typedef A parent; };
struct D : public std::array<double,5> { typedef std::array<double,5> parent; };
template<typename T> struct B : public uvector<T> { typedef uvector<T> parent; };
template<typename T> struct container_reference {};

// Catches 'false', A, C, D  ======== HERE IT IS !!! ========
template<typename C> struct accepted_dense_vector
{
    template<typename C1 = C>
    static typename std::enable_if<accepted_dense_vector<typename C1::parent>::value, std::true_type>::type helper(const C&);
    static std::false_type helper(...);

    constexpr static bool value = decltype(helper(std::declval<C>()))::value;
};
// Catches C<T>
template<template<typename> class C, typename T>
struct accepted_dense_vector<C<T>>
{
    constexpr static bool value = std::is_arithmetic<T>::value &&
        (std::is_base_of<uvector<T>, C<T>>::value || std::is_base_of<dynamic_array<T>, C<T>>::value);
};
// Catches std::array<T,S>
template<typename T, size_t S>
struct accepted_dense_vector<std::array<T,S>>
    { constexpr static bool value = std::is_arithmetic<T>::value; };

// Catches container_reference<C>
template<typename C>
struct accepted_dense_vector<container_reference<C>>
    { constexpr static bool value = accepted_dense_vector<C>::value; };

int main()
{ // Tests!
    cout << accepted_dense_vector<std::array<double, 5>>::value << endl;
    cout << accepted_dense_vector<uvector<double>>::value << endl;
    cout << accepted_dense_vector<A>::value << endl;
    cout << accepted_dense_vector<D>::value << endl;
    cout << accepted_dense_vector<B<int>>::value << endl;
    cout << accepted_dense_vector<container_reference<uvector<double>>>::value << endl;
    cout << accepted_dense_vector<int>::value << endl;

    return 0;
}

1 个答案:

答案 0 :(得分:1)

您可以进一步了解您的解决方案。首先,您不需要std::enable_if。代码将更具可读性。然后,使用将调用std::true_type

的自定义结构,而不是使用accepted_dense_vector
template<typename T>
struct forwarder
{
    constexpr static bool value = accepted_dense_vector<T>::value;
};

template<typename T>
static forwarder<uvector<T>> inherit_uvector(uvector<T>*);

static std::false_type inherit_uvector(...);

然后,要通过继承accepted...来了解类型是否满足uvector<T>,只需使用以下行:

constexpr static bool is_uvector = decltype(inherit_uvector(new C()))::value;
// C is the template parameter of accepted_dense_vector

这是如何运作的?

  • 如果C继承uvector<T>,则会选择第一个静态函数,而decltype将返回forwarder<uvector<T>>。然后,在其上“呼叫”::value将调用accepted...
  • 否则,如果C未继承uvector<T>,则会选择第二个函数,并且decltype将返回std::false_type

同样的技巧可以与其他遗产一起使用。此外,B<T>获得了accepted...的第二个专业化。因此,不再需要::parent typedef。

以下是完整代码(live here):

#include <iostream>
#include <array>
#include <string>
using namespace std;

// Definition of used types.
template<typename T> struct uvector {};
template<typename T> struct dynamic_array {};
template<typename T> struct container_reference {};

struct A : public uvector<double> {};
template<typename T> struct B : public uvector<T> {};
struct C : public A {};
struct D : public std::array<double,5> {};
struct E : public uvector<string> {};
struct F : public std::array<string,16> {};

// Catches 'false', A, C, D  ======== HERE IT IS !!! ========
template<typename C>
struct accepted_dense_vector
{
   template<typename T>
   struct forwarder
   {
      constexpr static bool value = accepted_dense_vector<T>::value;
   };

   // uvector
   template<typename T>
   static forwarder<uvector<T>> inherit_uvector(uvector<T>*);
   static std::false_type inherit_uvector(...);

   // std::array
   template<typename T, size_t S>
   static forwarder<std::array<T,S>> inherit_stdarray(std::array<T,S>*);
   static std::false_type inherit_stdarray(...);

   // same for dynamic_array<T>

    constexpr static bool is_uvector = decltype(inherit_uvector(new C()))::value;
    constexpr static bool is_stdarray = decltype(inherit_stdarray(new C()))::value;
    constexpr static bool value = is_uvector || is_stdarray;
};


// Catches C<T>
// /!\ Also catches anything which is template<typename> class (for example, B)
// => B::parent is not needed, because of the use of std::is_base_of
template<template<typename> class C, typename T>
struct accepted_dense_vector<C<T>>
{
    constexpr static bool value = std::is_arithmetic<T>::value &&
        (std::is_base_of<uvector<T>, C<T>>::value || std::is_base_of<dynamic_array<T>, C<T>>::value);
};

// Catches std::array<T,S>
template<typename T, size_t S>
struct accepted_dense_vector<std::array<T,S>>
{
   constexpr static bool value = std::is_arithmetic<T>::value;
};

// Catches container_reference<C>
template<typename C>
struct accepted_dense_vector<container_reference<C>>
{
   constexpr static bool value = accepted_dense_vector<C>::value;
};

int main()
{ // Tests!
    cout << "array = " << accepted_dense_vector<std::array<double, 5>>::value << endl;
    cout << "uvector = " << accepted_dense_vector<uvector<double>>::value << endl;
    cout << "ref = " << accepted_dense_vector<container_reference<uvector<double>>>::value << endl;
    cout << "A = " << accepted_dense_vector<A>::value << endl;
    cout << "B = " << accepted_dense_vector<B<int>>::value << endl;
    cout << "C = " << accepted_dense_vector<C>::value << endl;
    cout << "D = " << accepted_dense_vector<D>::value << endl;
    cout << "E = " << accepted_dense_vector<E>::value << endl;
    cout << "F = " << accepted_dense_vector<F>::value << endl;
    cout << "int = " << accepted_dense_vector<int>::value << endl;

    return 0;
}