Почему моя специализация шаблона функции отклонена VS2017, а не VS2015?

У меня есть класс свойств, который связывает типы с целочисленными значениями.

struct traits
{
  private:
    template<int ID> struct type_impl {};
    template<> struct type_impl<1> { using type = int; };
    // ...

  public:
    template<int ID> using type = typename type_impl<ID>::type;

};

Я пишу шаблонную функцию, тип возвращаемого значения которой предоставляется указанным выше классом признаков, и специализирую его на различных значениях int:

  template<int ID> traits::type<ID> function();
  template<> inline traits::type<1> function<1>() { return 42; };
  // ...

Это прекрасно компилируется с VS2015 (см. https://godbolt.org/z/LpZnni), но не с VS2017, который жалуется, что:

ошибка C2912: явная специализация 'int function‹1>(void)' не является специализацией шаблона функции

К моему удивлению, объявление функции, не являющейся шаблоном, как показано ниже, компилируется:

traits::type<1> other_function();

Открытие traits::type_impl решает проблему компиляции, но я не понимаю, почему. Для меня либо специализация, и объявление other_function должны компилироваться с traits::type_impl private или без.

Спасибо за помощь.

Дальнейшее расследование после комментария @rubenvb Я понимаю, что опубликованный мной код является незаконным, поэтому вместо этого я попытался сделать частичную специализацию (что я считаю законным):

struct traits
{
  private:
    template<int ID,bool=true> struct type_impl {};
    template<bool B> struct type_impl<1,B> { using type = int; };
    // ...

  public:
    template<int ID> using type = typename type_impl<ID>::type;

};

template<int ID> traits::type<ID> function();
template<> inline traits::type<1> function<1>() { return 42; };

Теперь все компиляторы довольны, но VS2017 все еще хочет traits::type_implpublic. Я предполагаю, что это ошибка Visual Studio.


person Yohann Bénédic    schedule 07.05.2019    source источник


Ответы (1)


У вас есть этот код

struct traits
{
  private:
    template<int ID> struct type_impl {};
    template<> struct type_impl<1> { using type = int; }; // HERE

  public:
    template<int ID> using type = typename type_impl<ID>::type;
};

template<int ID> traits::type<ID> function();
template<> inline traits::type<1> function<1>() { return 42; };

Строка, отмеченная //HERE, содержит специализацию шаблона внутри класса. Это незаконно в C++.

Из этого мы узнаем, что Visual Studio выдает ужасные сообщения об ошибках, когда задействованы шаблоны. Если проблема не сразу ясна, посмотрите, что говорит другой компилятор. Другой компилятор часто указывает на разные проблемы или говорит о них по-разному, что может, по крайней мере, дать хороший намек на то, где возникает реальная проблема.

Компилятор Intel показывает это:

error: explicit specialization is not allowed in the current scope
  template<> struct type_impl<1> { using type = int; };
  ^

GCC показывает это:

error: explicit specialization in non-namespace scope 'struct traits'
    5 |     template<> struct type_impl<1> { using type = int; };
      |              ^

Clang кажется, по какой-то причине не возражает. Кажется, это ошибка.

person rubenvb    schedule 07.05.2019
comment
Я не понимаю, чего не хватало в моем вопросе, который вы нашли по ссылке на божественную стрелу? - person Yohann Bénédic; 07.05.2019
comment
В любом случае, это прекрасно отвечает на мой вопрос, большое спасибо! - person Yohann Bénédic; 07.05.2019
comment
@ Йоханн Извини, мой плохой. Я прокрутил немного вниз и увидел только то, что хотел увидеть. Добро пожаловать! - person rubenvb; 07.05.2019
comment
Строка, отмеченная //HERE, содержит внутриклассовую специализацию шаблона функции Извините, какой именно шаблон функции специализирован в этой строке? - person Max Langhof; 07.05.2019
comment
Я только что заметил, что вы упомянули «специализацию функций» как незаконную внутри класса в своем ответе, но это специализация класса, которую я делаю. Я считаю, что полная специализация шаблона класса также недопустима внутри класса, но не частичная специализация. Поэтому я добавил фиктивный параметр шаблона, и это порадовало каждый компилятор, который я пробовал, за исключением VS, который по-прежнему хочет, чтобы все это было общедоступным. - person Yohann Bénédic; 07.05.2019
comment
Правильно, это не специализация шаблона функции, а специализация шаблона структуры. Хотя и то, и другое — ошибки. - person rubenvb; 08.05.2019