I am trying to understand whether the snippet below should compile according to The Standard or not. When I try to compile it with latest version of three major compilers, the following occurs:
-std=c++17
flag): compiles fine;-std=c++17
flag): also compiles fine;/std:c++17
flag): compiler error (see below).The error occurs because the MSVC compiler seemingly tries to instantiate std::optional<void>
despite the fact that the code is discarded. GCC and Clang don't seem to do that.
Does The Standard clearly define what should occur in this case?
#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;
}
Error by 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 ]
Live demo
Definitively a bug of MSVC. A bug report exist and has been reportedly fixed in Visual Studio 2019 Preview.
if constexpr
is standardized in [stmt.if]/2
:
If the
if
statement is of the formif constexpr
, the value of the condition shall be a contextually converted constant expression of type bool; this form is called a constexpr if statement.
This applies.
If the value of the converted condition is false, the first substatement is a discarded statement, otherwise [...].
It also applies, making in your program { std::optional<T> val; }
a discarded statement.
During the instantiation of an enclosing templated entity (ndYSC
Bar<void, int>
), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.
Along with @YSC's answer, also relevant is [temp.inst]/10
:
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement , unless such instantiation is required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With