使用外部类的模板参数设置内部模板类的默认模板参数

Posted

技术标签:

【中文标题】使用外部类的模板参数设置内部模板类的默认模板参数【英文标题】:Set default template parameters of an inner template class using template parameters of the outer class 【发布时间】:2013-09-04 20:45:58 【问题描述】:

以 Visual Studio C++ 2008 为目标

情况:我有一个带有大量参数的模板类,其中很多带有默认值。

template <typename A, typename B = b, typename C = c>
struct Outer

    typedef typename A typeA;
    typedef typename B typeB;
    typedef typename C typeC;
;

到目前为止一切顺利。现在,我有一个由大量Outers 组成的用户定义类型。在这种情况下,类型 A 和 B 是已知的,而 C 不是。

我处理这个问题的第一个方法就是在新的用户类型中复制 A 和 B。

template<typename A, typename B>
struct UserDefinedType 
    Outer<A, B, int> AnIntOuter;
    Outer<A, B, float> AFloatOuter;
;

这可行,但很快就会变得无聊。 (以及来自真实代码的其他复杂性)。我在想...为什么不使用作为默认值传入的模板参数创建一个新的内部类,所以我尝试这样做:

template<typename A, typename B>
struct AnotherUserDefinedType 
    template<typename CC, typename AA = A, typename BB = B>
    struct Inner : public Outer<AA, BB, CC> ;

    Inner<int> AnIntInner;
    Inner<float> AFloatInner;
;

当我尝试编译它时,我得到一个“模板参数太少”的错误,它似乎附加到成员的声明(在本例中为 AnIntInner)。

我想知道的是:这(使用外部类的模板参数作为内部类的默认模板参数)是否有可能?

如果可能,是我的构造错误还是 MSVC++ 2008 存在已知问题?或者,当然,如果我的代码中可能还有其他错误

更新

啊,辅助 20/20 后见之明总是很棒。我发现我的问题和我真正需要的答案至少有一个帽子戏法。

首先,@DyP 呼吁 SSCCE 是正确的,尽管我只缺少五行完整示例(如果我参加的是混淆 C++ 竞赛)我查看了我的代码并说“这看起来不错,所以我尝试过的新事物一定会导致问题”,我什至没有建立自己的例子。我需要处理我的编译器发出的模板错误消息解释(哦,是的,还有 ass-u-me-ing 部分......)。

但是,正如@nickie 礼貌地没有说的那样,这种结构是多余的。默认模板参数有它们的位置,但在这里,它甚至不需要。内部类可以看到外部类中使用的模板参数。最好只模板化我需要“免费”的参数。我认为@nickie 完美地回答了这个问题,尽管从技术上讲我一开始并没有错,所以@nickie 的回答得到了复选标记。

但这并没有结束。 @DyP 正确地直觉了我真正的问题,那就是我想对一些模板参数进行柯里化(在这里重新复制外部模板参数确实有它的用途,我们希望选择改变模板参数而不是将其紧密绑定为真正的柯里化确实(好吧,咖喱参数可能是一个仿函数......但我离题了))。我只需要类型,而不是扩展类。继承的问题在于它破坏了一些覆盖,即 operator=()。

所以,结合我们三个人的输入,我最终使用了这个结构

template<typename A, typename B>
struct FinalUserDefinedType 
    template<typename C, typename AWithDefault = A>
    struct CurryType 
        typedef Outer<AWithDefault, B, C> type;
    ;

    CurryType<int>::type AnIntOuter;
    CurryType<float>::type AFloatOuter;
    CurryType<double, int>::type AnOverriddenDefault;
;

更新 2

骗我一次,羞辱,骗我两次,送我到第九圈。

再一次,我没有编译我给出的示例。从我的真实代码中删除(@DyP 再次抓住了这个......),示例应该是:

template<typename A, typename B>
struct FinalUserDefinedType 
    template<typename C, typename AWithDefault = A>
    struct CurryType 
        typedef Outer<AWithDefault, B, C> type;
    ;

    typename CurryType<int>::type AnIntOuter;
    typename CurryType<float>::type AFloatOuter;
    typename CurryType<double, int>::type AnOverriddenDefault;
;

对于虚拟积分,是否可以在不使用typename的情况下声明AnIntOuter等?

【问题讨论】:

typedef typename A typeA; 没有 typename 在这里,拜托。 (见this question) 请提供SSCCE。 This example 在 VS2008 上编译良好。 顺便说一句:你不需要从Outer继承,你也可以使用typedef:template&lt;class CC, class AA=A, class BB=B&gt; struct Inner typedef Outer&lt;AA,BB,CC&gt; type; ;然后typename Inner&lt;int&gt;::type AnIntInner; 我知道 VS2008 不需要或强制执行它,但你应该在这里使用typenametypename CurryType&lt;int&gt;::type AnIntOuter; (等等)否则,你的代码将无法移植,你可能甚至遇到编译器问题(至少我从我的经验中猜测)。 Live example 【参考方案1】:

我认为这是做你想做的事情的正确方法(如果我理解正确的话):

template <typename A, typename B = b, typename C = c>
struct Outer

    typedef A typeA;
    typedef B typeB;
    typedef C typeC;
;

template<typename A, typename B>
struct AnotherUserDefinedType 
    template<typename C>
    struct Inner : public Outer<A, B, C> ;

    Inner<int> AnIntInner;
    Inner<float> AFloatInner;
;

【讨论】:

以上是关于使用外部类的模板参数设置内部模板类的默认模板参数的主要内容,如果未能解决你的问题,请参考以下文章

在成员数据中使用模板参数的模板类的基类指针

实验2:函数重载函数模板简单类的定义和实现

以类为参数调用模板类的静态模板方法

将可变参数模板类的模板参数解包为常量和常量数组

通过类的模板参数特化成员模板结构

第23课 可变参数模板_Optional和Lazy类的实现