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

Specialize member template struct by template parameters of class

本文关键字:成员 结构 形参      更新时间:2023-10-16

我有一个类,像

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. 正如peter指出的,有趣的是,在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
Visual Studio 2013中的

1
0

如果你取消注释,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

正如其他答案所提到的,这个问题看起来肯定是VS中的一个bug。在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的测试。