Непоследовательное поведение между компиляторами в отношении создания шаблона в отброшенном операторе constexpr (false) - PullRequest
0 голосов
/ 10 января 2019

Я пытаюсь понять, должен ли приведенный ниже фрагмент компилироваться в соответствии со стандартом или нет. Когда я пытаюсь скомпилировать его с последней версией трех основных компиляторов, происходит следующее:

  • Clang (версия 7.0.0, с флагом -std=c++17): отлично компилируется;
  • GCC (версия 8.2, с флагом -std=c++17): также хорошо компилируется;
  • MSVC (версия 19.16, с флагом /std:c++17): ошибка компилятора (см. Ниже).

Ошибка возникает из-за того, что компилятор MSVC пытается создать экземпляр std::optional<void>, несмотря на тот факт, что код отбрасывается. GCC и Clang, похоже, этого не делают.

Четко ли в стандарте определено, что должно произойти в этом случае?

#include <optional>  
#include <type_traits>
template<typename T, typename... Args>
struct Bar
{
  void foo(Args... args)
  {
    if constexpr(!std::is_same_v<T, void>) // false
    {
      // MSVC compiler error occurs because of the line below; no error occurs when compiling with GCC and Clang 
      std::optional<T> val; 
    }
  }
};
int main(int argc, char** argv)
{
  Bar<void, int> inst;
  inst.foo(1);
  return 0;
}

Ошибка MSVC:

C:/msvc/v19_16/include\optional(87): error C2182: '_Value': illegal use of type 'void'

C:/msvc/v19_16/include\optional(128): note: see reference to class template instantiation 'std::_Optional_destruct_base<_Ty,false>' being compiled
  with
  [
       _Ty=void
  ]

Демонстрационная версия

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Наряду с ответом @ YSC также имеет значение [temp.inst]/10:

Реализация не должна неявно создавать экземпляр шаблона функции, шаблона переменной, шаблона элемента, не виртуальной функции-члена, класса-члена, статического члена-данных шаблона класса или подстановки оператора constexpr if, если такое создание не требуется.

0 голосов
/ 10 января 2019

Определенно ошибка MSVC. отчет об ошибке существует и, как сообщается, был исправлен в Visual Studio 2019 Preview.


if constexpr стандартизировано в [stmt.if]/2:

Если оператор if имеет форму if constexpr, значение условия должно быть контекстно-преобразованным константным выражением типа bool; эта форма называется оператором constexpr if.

Это относится.

Если значение преобразованного условия равно false, первое подстановка - это отклоненный оператор , в противном случае [...].

Это также применимо, делая в вашей программе { std::optional<T> val; } a отвергнутый оператор .

Во время создания экземпляра вмещающего шаблонного объекта (ndYSC Bar<void, int>), если условие не зависит от значения после его создания, отброшенное подстановка (если есть) не создается .

...