C ++:使用内部typedef(如果在traits类或default中可用)

时间:2011-08-29 20:18:27

标签: c++ templates typetraits

我目前正在编写一个模板,根据输入的类别进行不同的操作。

我希望将3个案例添加到我的特质课程中。

  

一个。该类型有一个typedef type_category,使用它。

     

B中。该类型没有typedef,使用类型regular_tag(最常见的情况)

     

℃。我的专精std::list<T>使用special_tag类型T

我该如何管理?做A.和C.或B.和C.很简单。但我不知道如何获得所有3。

修改

一个例子可能会让人们更容易理解。

class Foo
{
    typedef foo_tag type_category;
}
class Bar;

my_traits<Foo>::type(); // makes a foo_tag
my_traits<Bar>::type(); // makes a regular_tag
my_traits<std::list<Baz>>::type(); // makes a special_tag because I want special list proce

ssing。

3 个答案:

答案 0 :(得分:7)

脚手架可能如下所示:

template <typename T>
struct MyTrait
{
  typedef typename MyHelper<T, CheckForType<T>::value>::type tag;
};

template <typename T>
struct MyTrait<std::list<T>>
{
  typedef special_tag tag;
};

我们需要帮手:

template <typename T, bool>
struct MyHelper
{
  typedef regular_tag tag;
};
template <typename T>
struct MyHelper<T, true>
{
  typedef typename T::type_category tag;
};

现在我们只需要一个类型特征来检查成员typedef:

template<typename T>
struct CheckForType
{
private:
    typedef char                      yes;
    typedef struct { char array[2]; } no;

    template<typename C> static yes test(typename C::type_category*);
    template<typename C> static no  test(...);
public:
    static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};

用法:

MyTrait<Foo>::tag

答案 1 :(得分:0)

template<class T> 
T::type_category getType(T t, typename T::type_category c=typename T::type_category()) 
{ return c;}
template<class T> 
regular_tag getType(T t, ...) 
{ return regular_tag();}
template<class T>
special_tag getType(std::list<T> t, typename std::list<T>::type_category c=typename std::list<T>::type_category()) 
{ return special_tag();}

int main() {
    auto a = getType(int);
    auto b = getType(std::iterator_traits<char*>);
    auto c = getType(std::list<char>);
}

我对SFINAE并不是那么好,所以我怀疑这甚至可以编译,但是这样的事情是看的方向。

答案 2 :(得分:0)

Kerrek的代码有效,但以下代码更短,更通用:

template <typename T,typename DefaultType>
class MyTrait
{
    template <typename C> static DefaultType               test( ... );
    template <typename C> static typename C::type_category test( typename C::type_category * );
public:
    using type = decltype( test<T>(nullptr) );
};

我之所以说Kerrek的代码不是通用的,是因为它要求你对类型进行硬编码&#34; special_tag&#34;所以你的类MyTrait将始终使用相同的默认标记。我提供的代码允许您使用具有不同默认值的MyTrait类。例如,如果未定义 type_category ,则可能会在代码中的某个位置发生默认为 int ,但在其他地方,您希望它是的即可。

让我们看一个例子。假设我们设计了一个类,它用于将容器类(例如标准库 vector )作为模板参数。在我们的课程中,我们希望使用相同的 size_type 作为基础容器。但是,有人可能会向我们提供一个未定义 size_type 的容器(例如, valarray 未定义 size_type )。在这种情况下,让我们假装我想使用 int 作为默认值(您应该像其他标准容器一样使用 size_t ,但如果我更改了代码你不能告诉代码实际上是有效的。对于这种情况,我改变了#34; MyTrait&#34;的类名。到&#34; size_typeof&#34;,我改变了&#34; type_category&#34;到&#34; size_type&#34; (因为这是我想要寻找的东西)。下面给出了此场景的一些代码以及用于查看确定变量类型的示例main函数:

#include <iostream>
#include <vector>
#include <valarray>
#include <typeinfo>

template <typename T,typename DefaultType>
class size_typeof
{
    template <typename C> static DefaultType           test( ... );
    template <typename C> static typename C::size_type test( typename C::size_type * );
public:
    using type = decltype( test<T>(nullptr) );
};

template <typename ContainerType>
class Matrix {
    private:
        // Change int to size_t in real code. 
        using size_type = typename size_typeof<ContainerType,int>::type;
        size_type Rows;
        size_type Cols;
    public:
        Matrix( size_t rows, size_t cols ) : Rows(rows), Cols(cols) {}
        size_type rows(){ return Rows; }
        size_type cols(){ return Cols; }
};

int main()
{
    // Give the matrices some nonzero dimensions
    Matrix<std::vector<double>> vec(5,2);
    Matrix<std::valarray<double>> val(4,3);

    // vectors have a size_type, almost always defined as size_t. 
    // So this should return your compiler's code for size_t 
    // (on my computer, this is "m")
    std::cout << typeid( vec.rows() ).name() << std::endl; 

    // valarrays do not have a size_type. 
    // So this should return your compiler's code for int 
    // (on my computer, this is "i")
    // It should return this code, since we used int as the default  
    // size_type in the Matrix class
    std::cout << typeid( val.rows() ).name() << std::endl; 
    return 0;
}

确定。太棒了。但是假设我确实只想使用DefaultType的硬编码默认值,而不必将DefaultType指定为模板参数。你猜怎么着?模板参数默认值。只需定义size_typeof,如:

template <typename T,typename DefaultType = int>
class size_typeof {
    ...
};

你很高兴。无需指定默认类型&#34; int&#34;了。例如,在我们的Matrix类中,我们可以使用

using size_type = size_typeof<ContainerType>;

结束。