编译器中关于在丢弃的if constexpr(false)语句中实例化模板的行为不一致

Nej*_*ejc 19 c++ language-lawyer c++17

我试图了解下面的代码段是否应该根据标准进行编译.当我尝试使用最新版本的三个主要编译器编译它时,会发生以下情况:

  • 锵(7.0.0版本,-std=c++17标志):编译罚款;
  • ✓GCC(版本8.2,带-std=c++17标志):也编译好;
  • ❌MSVC(版本19.16,带/std:c++17标志):编译器错误(见下文).

发生此错误是因为std::optional<void>尽管代码被丢弃,MSVC编译器似乎试图实例化.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;
}
Run Code Online (Sandbox Code Playgroud)

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
  ]
Run Code Online (Sandbox Code Playgroud)

现场演示

YSC*_*YSC 19

绝对是MSVC的一个错误.一个错误报告存在,据说已被固定在Visual Studio 2019预览.


if constexpr标准化为[stmt.if]/2:

如果if语句是格式if constexpr,则条件的值应为bool类型的上下文转换常量表达式; 此表单称为constexpr if语句.

这适用.

如果转换条件的值为false,则第一个子语句废弃语句,否则[...].

它也适用于你的程序中{ std::optional<T> val; }废弃语句.

在封闭模板化实体(ndYSC Bar<void, int>)的实例化期间,如果条件在其实例化之后不依赖于值,则不实例化丢弃的子语句(如果有的话).


P.W*_*P.W 5

与@ YSC的答案一样,相关的还有[temp.inst]/10:

实现不应隐式实例化函数模板,变量模板,成员模板,非虚拟成员函数,成员类,类模板的静态数据成员或constexpr if语句的子语句,除非这样的实例化是必须的.