Почему моя специализация шаблона функции отклонена VS2017, а не VS2015? - PullRequest
4 голосов
/ 07 мая 2019

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

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 или none.

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

Дальнейшее расследование после комментария @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_impl публичность.Я предполагаю, что это ошибка Visual Studio.

1 Ответ

4 голосов
/ 07 мая 2019

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

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 , кажется, не против по какой-то причине. Это похоже на ошибку.

...