3

My compiler is gcc 4.9.0. The following code cannot be compiled:

template<typename T, T i>
struct value {};

template<typename T>
struct value<T, 0> {};
// error: type 'T' of template argument '0' depends on a template parameter

What is the cause? and, how to solve this issue?

xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • How to solve this issue? -> see the answers to the following questions for some workarounds: [(Partially) specializing a non-type template parameter of dependent type](http://stackoverflow.com/questions/22486386/partially-specializing-a-non-type-template-parameter-of-dependent-type/22486607#22486607) and [Dependant non-type template parameter and variadic template](http://stackoverflow.com/questions/23228894/dependant-non-type-template-parameter-and-variadic-template?lq=1). – Constructor Jul 11 '14 at 12:33

2 Answers2

8

GCC is right, this is explicitly forbidden by C++11 [temp.class.spec] §8:

8 Within the argument list of a class template partial specialization, the following restrictions apply:

  • A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier. [ Example:

    template <int I, int J> struct A {};
    template <int I> struct A<I+5, I*2> {}; // error
    template <int I, int J> struct B {};
    template <int I> struct B<I, I> {}; // OK
    

    —end example ]

  • The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the specialization. [ Example:

    template <class T, T t> struct C {};
    template <class T> struct C<T, 1>; // error
    template< int X, int (*array_ptr)[X] > class A {};
    int array[5];
    template< int X > class A<X,&array> { }; // error
    

    —end example ]

  • ...

I believe point 2 is the most relevant one here.


Regarding the question of "how to solve this issue." In the form the question stands now, there is no workaround, I am afraid.

As for the original vesion with making integer sequences, I believe that you could make it work with using uintmax_t for the type of the non-type template parameter, and only convert it to intT in the final definition.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Where is the solution? – xmllmx Jul 09 '14 at 14:28
  • 1
    @Angew: Goodness, I battled at it and it was really stubborn... glad you managed it! – Matthieu M. Jul 09 '14 at 14:31
  • @xmllmx You asked why it doesn't work, not how to make it work. The shortened version of your question has a simple answer "this cannot work." The original one might have a different solution, though. Still, the question was "why?" – Angew is no longer proud of SO Jul 09 '14 at 14:33
  • @MatthieuM. I sometimes forget how badly copies from the standard PDF look unedited. – Angew is no longer proud of SO Jul 09 '14 at 14:34
  • 1
    @xmllmx: The solution involves not using partial specialization I would guess. Do you actually need those integer sequences you were mentioning ? They already exist in C++14 ([see here](http://en.cppreference.com/w/cpp/utility/integer_sequence)). – Matthieu M. Jul 09 '14 at 14:39
  • @MatthieuM. I just want to know how C++14's `integer_sequence` works. – xmllmx Jul 09 '14 at 14:42
  • @xmllmx: http://llvm.org/svn/llvm-project/libcxx/trunk/include/utility (search for `integer_sequence` and do not stop on the first few hits which are part of the sum-up of what the header contains). – Matthieu M. Jul 09 '14 at 14:47
  • @MatthieuM. I think clang's implementation is ugly. I'm learning gcc's. – xmllmx Jul 09 '14 at 14:55
  • LLVM's implementation is quite strange, GNU's is shorter and easier to read, looking more like the "obvious" implementation: https://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=libstdc%2B%2B-v3/include/std/utility – Oktalist Jul 09 '14 at 15:19
  • @Oktalist: libc++'s implementation is optimized to reduce the number of recursive steps which in turns speeds up computation. This does not matter, however, what matters is the `__convert` trick: the recursion is done on a fixed type (`size_t`) and then the integers are converted to another type depending on what was asked. – Matthieu M. Jul 09 '14 at 15:48
0

use std::integral_constant instead of a integer literal directly:

template<typename T, typename VALUE>
struct value;

template<typename T>
struct value<T, std::integral_constant<T, 0> >
{
};

this worked fine for me, when trying to implement std::make_integer_sequence for C++11....