存储指向同一模板类

时间:2016-02-26 02:17:20

标签: c++ templates c++11

假设我们有以下内容:

template<typename A, typename B>
class Foo {
private:
    A m_a;
    B m_b;
    Foo<A,B>* m_pFoo;

public:
    Foo( A a, B b, Foo<A,B>* pFoo = nullptr );
};

使用此类,只要实例化,我就可以将pFoo保存到m_pFoo 类型匹配如下:

 int main() {
     Foo<int, int> foo1( 3, 5 );
     Foo<int, int> foo2( 2, 4, &foo1 ); // This Works
     Foo<int, int> foo3( 5, 7, &foo2 ); // This Still Works 

     Foo<double, int> foo4( 2.4, 5 );
     Foo<double, int> foo5( 7.5, 2, &foo4 ); // This Works
     Foo<double, int> foo6( 9.2, 6, &foo5 ); // This Still Works

     // Compiler Error - Can not deduce template arguments
     Foo<double, int> foo7( 3.7, 2, &foo1 ); // Doesn't Work

     return 0;
 }

在之前的一个问题中,我演示了一个与此类似的问题,我最初的问题是如何将指向类模板类型的指针传递到同一个类模板构造函数中,但我收到的关于此的一个响应是传入指针不是问题,但存储是。所以在这篇文章中我的新问题就变成了这个:

我如何能够使用与上述相同或类似的构造函数具有相同的类模板,其中每种类型都是:

Foo<short, short>           ssFoo;
Foo<short, int>             siFoo;
Foo<short, int64_t>         si64Foo;
Foo<short, unsigned>        suFoo;
Foo<short, float>           sfFoo;
Foo<short, double>          sdFoo;
Foo<short, long>            slFoo;
Foo<short, long long>       sllFoo;

Foo<int, short>             isFoo;
Foo<int, int>               iiFoo;
Foo<int, int64_t>           ii64Foo;
Foo<int, unsigned>          iuFoo;
Foo<int, float>             ifFoo;
Foo<int, double>            idFoo;
Foo<int, long>              ilFoo;
Foo<int, long long>         illFoo;

Foo<int64_t, short>        i64sFoo;
Foo<int64_t, int>          i64iFoo;
Foo<int64_t, int64_t>      i64i64Foo;
Foo<int64_t, unsigned>     i64uFoo;
Foo<int64_t, float>        i64fFoo;
Foo<int64_t, double>       i64dFoo;
Foo<int64_t, long>         i64lFoo;
Foo<int64_t, long long>    i64llFoo;

Foo<unsigned, short>        usFoo;
Foo<unsigned, int>          uiFoo;
Foo<unsigned, int64_t>      ui64Foo;
Foo<unsigned, unsigned>     uuFoo;
Foo<unsigned, float>        ufFoo;
Foo<unsigned, double>       udFoo;
Foo<unsigned, long>         ulFoo;
Foo<unsigned, long long>    ullFoo;

Foo<float, short>           fsFoo;
Foo<float, int>             fiFoo;
Foo<float, int64_t>         fi64Foo;
Foo<float, unsigned>        fuFoo;
Foo<float, float>           ffFoo;
Foo<float, double>          fdFoo;
Foo<float, long>            flFoo;
Foo<float, long long>       fllFoo;

Foo<double, short>          dsFoo;
Foo<double, int>            diFoo;
Foo<double, int64_t>        di64Foo;
Foo<double, unsigned>       duFoo;
Foo<double, float>          dfFoo;
Foo<double, double>         ddFoo;
Foo<double, long>           dlFoo;
Foo<double, long long>      dllFoo;

Foo<long, short>            lsFoo;
Foo<long, int>              liFoo;
Foo<long, int64_t>          li64Foo;
Foo<long, unsigned>         luFoo;
Foo<long, float>            lfFoo;
Foo<long, double>           ldFoo;
Foo<long, long>             llFoo;
Foo<long, long long>        l_llFoo;

Foo<long long, short>       llsFoo;
Foo<long long, int>         lliFoo;
Foo<long long, int64_t>     lli64Foo;
Foo<long long, unsigned>    lluFoo;
Foo<long long, float>       llfFoo;
Foo<long long, double>      lldFoo;
Foo<long long, long>        ll_lFoo;
Foo<long long, long long>   ll_llFoo;

构造时是否所有有效类型都存储在类模板中,其中前一个实例的地址被传递到新实例的构造函数中?也;我怎么能阻止这个类接受任何自定义或用户定义的对象或字符,字符串类型,枚举和布尔类型?我希望将typenames作为数值类型传递到类模板参数列表中。

2 个答案:

答案 0 :(得分:3)

模板的实例是完全不同的类型,与所有其他类型以及模板的其他实例分开。

Foo<short, short>

Foo<int, int>

是两个不同的类,它们彼此不同

Foo1;

Foo2;

彼此不同。

这些是不同的类。由此得出:

Foo<short, short> *m_pFoo;

Foo<int, int> *m_pFoo;

也与

相同

Foo1 *m_pFoo;

Foo2 *m_pFoo;

是。 C ++就是这样做的。模板的m_pFoo成员只能指向一个类。你必须选择它是哪一个。它可以是与其自己的类相同的类型,这是一个选项。或者,它可以指向其他类的实例。但它只能是一个班级。

当然,除非你做到了

void *m_pFoo;

但是,当然,你会失去类型安全和类型检查,走这条路。

正如评论中提到的那样,您可以从超类派生模板,并存储指向超类的指针:

class FooBase {

// ...

};

template<typename A, typename B> class Foo : public FooBase {

    A m_a;
    B m_b;
    FooBase* m_pFoo;

public:
    Foo( A a, B b, FooBase* pFoo = nullptr );
};

因此,您将能够将指向任何Foo<A, B>的指针传递给构造函数,该构造函数将自动转换为超类,并且只会存储指向超类的指针。

当然,这种方法还有许多其他含义,但这是最干净,最类型安全的方法 - 至少到目前为止 - 我能想到的。

答案 1 :(得分:1)

让我们先解决编译错误及其原因: 无法推断模板参数的原因是因为构造函数接受指向类型Foo<A, B>的指针。定义foo7时,你创建了一个类型为Foo<double, int>的foo7。然后,您尝试将对foo1的引用传递给其Foo<int, int>类型的参数,但构造函数需要Foo<double, int>

为了解决这个问题,可以创建第三个模板类型,以便能够接受任何其他类型的Foo,同时不限制正在构造的当前类型。如果措辞不好,我道歉。我写了一个例子:

template<typename A, typename... Rest>
class Foo;

template<typename A, typename B, typename C>
class Foo<A, B, C>{
private:
    A m_a;
    B m_b;
    C* m_pFoo;

public:
    Foo(A a, B b, C* p_Foo);
};

template<typename A, typename B>
class Foo<A, B>{
private:
    A m_a;
    B m_b;
    Foo<A, B>* m_pFoo;

public:
    Foo(A a, B b, Foo<A, B>* p_Foo = nullptr);
};

在这里,我们声明了一个可以接受1个或更多模板参数的类Foo。接下来,有一个Foo的定义,它接受三个模板参数,一个Foo只接受两个模板参数。 使用三参数定义,我们有第三种类型,它将是m_pFoo指针的类型。在双参数定义中,我们将m_pFoo声明为类型Foo<A, B>*(这是原始代码的初始行为)

int main() {
    Foo<int, int> foo1(3, 5);
    Foo<int, int, decltype(foo1)> foo2(2, 4, &foo1); 
    Foo<int, int, decltype(foo2)> foo3(5, 7, &foo2); 

    Foo<double, int> foo4(2.4, 5);
    Foo<double, int, decltype(foo4)> foo5(7.5, 2, &foo4);
    Foo<double, int, decltype(foo5)> foo6(9.2, 6, &foo5); 

    //Now works.
    Foo<double, int, decltype(foo1)> foo7(3.7, 2, &foo1); 

    return 0;
} 

现在我们可以使用decltype(在C ++ 11中添加)将foo实例的类型作为模板参数传递。

它不是'自动',仍然要求你明确说明要传递给构造函数的foo的类型,但我认为这应该与你想要做的非常接近。