【问题标题】:Partial specialization with type nested in a templated class嵌套在模板类中的类型的部分特化
【发布时间】:2023-03-27 08:00:01
【问题描述】:

我正在使用模板和部分专业化,但有一个专业化我不知道如何编写...我将简化代码以使其更易于阅读。

让我们考虑

template <typename T>
    class x
{
    ...
};

通常,我可以这样专攻:

class x<a_type>
{
    ...
};

也适用于模板类型:

template <typename T>
    class x<std::vector<T>>
{
    ...
}

现在我想对嵌套在模板类中的类型进行特化:

template <typename T>
    class y
{
    struct nested_type
    {
        y a_member;
    };

    ...
};

// Here comes the specialization

template <typename T>
    class x<y<T>::nested_type>
{
    ...
};

这失败了。我还尝试将 'typename' 放在 y::nested_type 之前,但它并没有解决问题。编译错误是:

type/value mismatch at argument 1 in template parameter list for ‘template <class T> struct x’

我想做的事情似乎合乎逻辑,但我不确定它是否可能。我将 C++0x 与 g++-4.5 一起使用。有人知道编写这种专业化的正确语法吗?

【问题讨论】:

  • 我认为您需要编辑问题。它应该是class x&lt;....&gt;,而不是前两个块中的class&lt;....&gt;。你确定你已经仔细输入了 everything 吗?
  • 是的,你是对的。这只是我的消息中的一个小错误,因为我没有复制我的代码,而是更喜欢使用 x 或 y 来简化问题。我确实尝试了较小的示例,但 Mikael 的答案似乎不错 - 我无法使小示例起作用,相信我,我尝试了很多东西!
  • 请注意,如果您使用“正确”语法template&lt;typename T&gt; class x&lt;typename y&lt;T&gt;::nested_type&gt; 而不是template&lt;typename T&gt; class x&lt;y&lt;T&gt;::nested_type&gt;(添加typename),则会从GCC 收到更合理的错误消息。

标签: c++ templates specialization


【解决方案1】:

答案是你不能做这个专业化。这不是语法错误,而只是无法实现的东西。你必须看到模板特化有点像函数重载。编译器必须在使用站点获取类型参数,查看可用的特化,找到匹配项,然后选择最好的(最特化的)。您的示例的问题在于,通过这种专业化无法实现“查找匹配”步骤。编译器可以期望“nested_type”是任何东西,不一定是唯一类型(如您的示例中那样),它也可以是嵌套 typedef,例如。此外,编译器无法预测它已经看到模板“y”的所有特化,因此即使nested_type 是嵌套在 y(通用模板)中的唯一类型,它也可能是即将到来的模板特化声明中的嵌套 typedef 模板“是”。

就像函数重载和那里使用的匹配算法一样,编译器在推断类型的能力方面受到限制,而限制是它可以做出多少假设。如果您对x&lt;int&gt; 有专门化,然后使用x&lt;int&gt;,则匹配是微不足道的,不需要推论,不需要假设。如果你有像x&lt;T*&gt;这样的特化,后来又用x&lt;int*&gt;,那么匹配很容易,T可以推导出为int。如果你有像x&lt; y&lt;T&gt;::type &gt; 这样的专业化然后使用任何版本的x,编译器应该如何从y::type 推导出T?它必须用 T in y 替换整个世界中存在的所有可能类型,以查看是否有一个导致匹配的嵌套类型。这是一个不合理的期望,这就是为什么 C++ 模板的类型推导功能到此为止。很多时候,要知道您是否应该期望编译器能够解决某些问题,只需设身处地为它着想,看看它是否有可能(答案通常很清楚)。

【讨论】:

  • 好吧,我想如果我使用x&lt;y&lt;int&gt;::type&gt;,编译器可以推断出y&lt;int&gt;::type,然后找到x的正确特化。您所说的确实有道理,我知道编译器无法从x&lt;y&lt;T&gt;::type&gt; 推断出T,但是,在我的情况下,指示T,因此可以推断出y&lt;T&gt;::type,从而启用专业化解析。作为一种解决方法,我将在类之外声明我的嵌套结构。感谢您的回复。
  • 是的,当然,问题不在于预期的用例(例如x&lt; y&lt;int&gt;::type &gt;),而是必须针对该专业化检查所有其他用例以确定它是否可以匹配它并检查匹配是不可能的,因为要么必须考虑无限数量的情况,要么必须做出不合理的假设(假设y&lt;T&gt;::type 绝不是与 y“无关”的类型的 typedef)。
【解决方案2】:

您确实不能进行这种部分专业化,但是有一种解决方法可以使用它来达到预期的效果。

而不是专门化,强制目标类型实现你所需要的。

这是一个最小的例子:

#include <vector>
#include <iostream>
#include <cassert>

// Default template defines an interface against the target type.
template <class T> struct Traits
{
    using TraitsType = typename T::foo_type;

    static void foo()
    {
        T::foo();
    }
};

// This is the sample class.
template <class T> struct MyStuff
{
    struct NestedType
    {
        int x;

        // It implements the desired features.
        using foo_type = int;
        static void foo()
        {
            std::cout << "Using Nested version!\n";
        }
    };
};

// For built in types you can use specialization.
template <> struct Traits<int>
{
    using TraitsType = double;

    static void foo()
    {
        std::cout << "Using int version.\n";
    }
};

//... If you can't touch the nested type, the you are SOL.


int main()
{
    static_assert(std::is_same<Traits<int>::TraitsType, double>::value);
    static_assert(std::is_same<Traits<MyStuff<int>::NestedType>::TraitsType, int>::value);
    static_assert(std::is_same<Traits<MyStuff<double>::NestedType>::TraitsType, int>::value);

    Traits<int>::foo(); // Prints "Using int version"
    Traits<MyStuff<int>::NestedType>::foo(); // Prints "Using Nested version!\n"
    Traits<MyStuff<double>::NestedType>::foo(); // Prints "Using Nested version!\n"

    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-12
    • 2016-01-11
    • 2022-01-21
    • 2018-11-26
    • 2017-09-20
    • 1970-01-01
    相关资源
    最近更新 更多