1

I have a class like

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

what I want to realize is to cout "1" when P==N, however I found when I run

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

it still gives 0.

Later I found when there is only one parameter in the template list it works:

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

though it looks simple, but what is the mechanism there, and how should I make it work when there two parameters?

EDIT

  1. As m.s. has pointed out that, this code can do its job on a gcc compiler on Wandbox, but it just fails on my vs2013. Anyone knows why?

  2. As Petr points out, the funny thing is that on MSVS, when P==I the result is "1".

  3. When I changed the code to:

    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(); gives "1".

Petr
  • 9,812
  • 1
  • 28
  • 52
Kozuki
  • 97
  • 8
  • output is "1" for your original code here: http://melpon.org/wandbox/permlink/CyW5VmcwsFteOys0 – m.s. Oct 26 '15 at 07:15
  • @m.s. I tested it, it's amazing. I got a different result compiling by my vs2013. – Kozuki Oct 26 '15 at 07:24
  • @m.s, outputs 0 for me on VS2013 too, and 1 on gcc 4.8.2. – Petr Oct 26 '15 at 08:17
  • The most funny thing is that `TEST<2>::test<10, 10>::Run();` prints `1` for me on MSVS2013! – Petr Oct 26 '15 at 08:25
  • @Petr yes that's the same as me. when 'P==I' its "1". – Kozuki Oct 26 '15 at 08:28
  • @Kozuki, I think that `compiler-construction` is not a tag that matches your question (unless you really want to know what is the inner working of VS that leads to this result), and both metaprogramming tags also do not apply here. Instead, `visual-studio` seems to be a relevant tag. I've edited this, if you do not agree, you can revert the edit. – Petr Oct 26 '15 at 08:52
  • Yes, it's probably a vs bug. – n. m. could be an AI Oct 26 '15 at 08:58
  • Although check also http://stackoverflow.com/questions/4944156/partial-specialization-of-double-templated-method-fails : "You cannot specialize a member template without also specializing the class template." Trying to understand whether that applies to this case. @n.m. – Petr Oct 26 '15 at 09:01
  • @Petr I don't think this applies. You cannot specialize e.g. `TEST<1>::test` without specializing `TEST<1>`. This is a different case. – n. m. could be an AI Oct 26 '15 at 09:41

2 Answers2

1

The following full code (I removed __forceinline to make it compatible with 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;
}

outputs

0
1

on Visual Studio 2013, and

1
0

on gcc 4.8.2.

If you uncomment the commented line, gcc is giving the expected result of 1 2, while VS does not compile with the following error:

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>'

So MSVS seems to take the (first) specialization to be for P==I, not for N==P. This definitely looks to be a bug in Visual Studio.

Petr
  • 9,812
  • 1
  • 28
  • 52
1

As mentioned by other answers, this problem definitely looks to be a bug in VS. Before MS fix this bug, I found one solution to realize the same function:

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

which gives "1" when P==N, otherwise "0". The above solution has passed tests on both VS2013 and gcc5.2.0.

Kozuki
  • 97
  • 8