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

Posted

技术标签:

【中文标题】通过类的模板参数特化成员模板结构【英文标题】: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;  ;
;

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

编辑

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

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

    当我将代码更改为:

    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”时。 【参考方案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上均通过测试。

【讨论】:

以上是关于通过类的模板参数特化成员模板结构的主要内容,如果未能解决你的问题,请参考以下文章

C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)

通过类模板特化访问成员数据

Clang 是不是正确拒绝仅通过特化定义类模板的嵌套类的代码?

在派生类中专门化模板成员

通过模板的特化实现 简单的类型萃取 实现memcppy时候对于特殊类型如string类的拷贝。

2020春招字节跳动二面