【问题标题】:Specialize member template struct by template parameters of class通过类的模板参数特化成员模板结构
【发布时间】:2015-10-26 07:13:07
【问题描述】:

我有一门课

template <unsigned N>
class TEST {
public:
    template <unsigned P, unsigned I>   struct test         { static __forceinline void Run() { std::cout << 0 << std::endl; } };
    template <unsigned I>               struct test <N, I>  { static __forceinline void Run() { std::cout << 1 << std::endl; } };
};

我想实现的是cout“1”当P==N,但是我在运行时发现

TEST<0>::test<0, 10>::Run();

它仍然给出0

后来我发现当模板列表中只有一个参数时它起作用了:

template <unsigned N>
class TEST {
public:
    template <unsigned P>   struct test         { static __forceinline void Run() { std::cout << 0 << std::endl; } };
    template <>             struct test <N>     { static __forceinline void Run() { std::cout << 1 << std::endl; } };
};

虽然看起来很简单,但其中的机制是什么,当有两个参数时我应该如何使其工作?

编辑

  1. 作为 m.s.已经指出,这段代码可以在Wandbox 上的 gcc 编译器上完成它的工作,但它在我的 vs2013 上失败了。有人知道为什么吗?

  2. 正如 Petr 所指出的,有趣的是在 MSVS 上,当P==I 结果为“1”时。

  3. 当我将代码更改为:

    template <typename N>
    class TEST {
    public:
    template <typename P, unsigned I>   struct test         { static __forceinline void Run() { std::cout << 0 << std::endl; } };
    template <unsigned I>               struct test <N, I>  { static __forceinline void Run() { std::cout << 1 << std::endl; } };
    };
    

TEST&lt;int&gt;::test&lt;int, 10&gt;::Run(); 给出“1”。

【问题讨论】:

  • 原始代码的输出为“1”:melpon.org/wandbox/permlink/CyW5VmcwsFteOys0
  • @m.s.我测试过,很神奇。我的 vs2013 编译得到了不同的结果。
  • @m.s,在 VS2013 上也为我输出 0,在 gcc 4.8.2 上为我输出 1。
  • 最搞笑的是TEST&lt;2&gt;::test&lt;10, 10&gt;::Run();在MSVS2013上为我打印1
  • @Petr 是的,这和我一样。当“P==I”为“1”时。

标签: c++ visual-studio templates partial-specialization


【解决方案1】:

以下完整代码(我删除了__forceinline以使其与gcc兼容):

#include <iostream>

template <unsigned N>
class TEST {
public:
    template <unsigned P, unsigned I>   struct test         { static void Run() { std::cout << 0 << std::endl; } };
    template <unsigned I>               struct test <N, I>  { static void Run() { std::cout << 1 << std::endl; } };
//  template <unsigned I>               struct test <I, I>  { static void Run() { std::cout << 2 << std::endl; } };
};
int main() {
    TEST<2>::test<2, 10>::Run();
    TEST<2>::test<10, 10>::Run();
    return 0;
}

输出

0
1

在 Visual Studio 2013 上,以及

1
0

在 gcc 4.8.2 上。

如果您取消注释注释行,gcc 将给出预期结果1 2,而 VS 无法编译并出现以下错误:

1>source.cpp(12): error C2752: 'TEST<2>::test<10,10>' : more than one partial specialization matches the template argument list
1>          source.cpp(7): could be 'TEST<N>::test<N,I>'
1>          source.cpp(8): or       'TEST<N>::test<I,I>'

因此,MSVS 似乎将(第一个)专业化用于P==I,而不是N==P。这绝对看起来是 Visual Studio 中的一个错误。

【讨论】:

    【解决方案2】:

    正如其他答案所提到的,这个问题肯定看起来是 VS 中的一个错误。 在MS修复这个bug之前,我找到了一个实现相同功能的解决方案:

    template <unsigned N>
    class TEST {
    public:
        template <unsigned P, unsigned I, bool Specialize = (N==P)> struct test             { static void Run() { std::cout << 0 << std::endl; } };
        template <unsigned P, unsigned I>                           struct test <P,I,true>  { static void Run() { std::cout << 1 << std::endl; } };
    };
    

    P==N 时给出“1”,否则给出“0”。 上述方案在VS2013和gcc5.2.0上均通过测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-11
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多