通过 class 的模板参数专门化成员模板结构

Specialize member template struct by template parameters of class

我有一个class喜欢

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; } };
};

我想实现的是在 P==Ncout “1”,但是我发现 运行

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<int>::test<int, 10>::Run(); 给出“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

2013 年 Visual Studio,并且

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.

中的错误

正如其他答案所提到的,这个问题看起来肯定是VS中的一个错误。 在微软修复这个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上都通过了测试