1

After answering this question I decided to dig deeper in the issue to find a minimal and replicable example with same error.

Let assume I have the following primary template and I would like to specialize it to std::vector as follows:

#include <vector>
#include <iostream>

template<typename T, typename T::value_type v>
struct foo;

template<typename T, T v>
struct foo<std::vector<T>, v> {
    static constexpr T value = v;
};

int main() {
    std::cout << foo<std::vector<int>, 32>::value << std::endl;
    return 0;
}

GCC 7.1.0 won't compile the code above with -std=c++11, -std=c++14 or -std=c++1z neither the experimental GCC 8.0.0 but only with -std=c++11 or -std=c++14. They produce the same error output:

prog.cc:8:12: error: partial specialization 'struct foo<std::vector<T>, v>' is not more specialized than [-fpermissive]
     struct foo<std::vector<T>, v> {
            ^~~~~~~~~~~~~~~~~~~~~~
prog.cc:5:12: note: primary template 'template<class T, typename T::value_type v> struct foo'
     struct foo;
            ^~~

The presented example works well with GCC 6.3.0 and at least with GCC 4.5.4.

Could anyone confirm that this is a compiler bug? Is there any workaround with GCC 7.1.0 to make my example work?

Akira
  • 4,385
  • 3
  • 24
  • 46
  • 1
    The Standard recently adapted the rule "The specialization shall be more specialized than the primary template.". Try to create a function template overload with the template parameters of the class templates (and specialization) respectively and with the parameter type `foo` and `foo, v>`, and see whether the compiler complains about an ambiguity. If so, then GCC appears to be consistent, at least. Also compare with Clang. – Johannes Schaub - litb Jun 23 '17 at 08:51
  • .. and I think that GCC is correct here: `foo, v>` does not deduce the argument `foo`, since `T` can be anything. And `foo` (with `v` being of type `typename std::vector::value_type`) cannot deduce argument `foo, v>` (with `v` being of type `anything`) because the types of the non-type parameter differ (for the last part, I can't find a definitive quote though... But since `anything` is an invented symbolic type, I can't see how it could possibly bridge the type difference). – Johannes Schaub - litb Jun 23 '17 at 09:11
  • This example however compiles with GCC8, and only fails with GCC7 on wandbox: https://wandbox.org/permlink/BG0lnc02aFY6AUus . So it appears that they think that the type difference doesn't matter, and it deduces `v`. Clang also accepts the overload set and succeeds in the call. – Johannes Schaub - litb Jun 23 '17 at 09:21
  • @JohannesSchaub-litb, I just tried my example with `foo` and `foo>` and despite the `T` can be anything, it works with all GCC versions listed at Wandbox: https://wandbox.org/permlink/p9c3AWS5o5JLJCqe. – Akira Jun 23 '17 at 10:00
  • 1
    As a workaround, `template::value_type v> struct foo, v> {...};` works with GCC 7.0. Somehow, it seems to have difficulty determining that `T` and `std::vector::value_type` are one and the same. – Igor Tandetnik Jun 23 '17 at 13:18
  • @IgorTandetnik This is a great workaround, works perfectly. – Akira Jun 25 '17 at 11:41

0 Answers0