Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

if constexpr inside lambda, differing compiler behavior

Tags:

Consider the following code. If my understanding of if constexpr is correct, the else branch should not be compiled so the z() should not be considered an error.

#include <type_traits>

struct Z{};

template<typename T>
void f(T z) {
  auto lam = [z]() {
    if constexpr(std::is_same<T, Z>::value) {
    } else {
      z();
    }
  };
}

int main() {
  f(Z{});
}

In clang and gcc this compiles; but with latest MSVC it does not. Unfortunately goldbolt's MSVC is too old, but on my machine with fully updated VS 2017, cl /std:c++17 yields:

Microsoft (R) C/C++ Optimizing Compiler Version 19.14.26428.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

if_constexpr.cpp
if_constexpr.cpp(10): error C2064: term does not evaluate to a function taking 0 arguments
if_constexpr.cpp(16): note: see reference to function template instantiation 'void f<Z>(T)' being compiled
        with
        [
            T=Z
        ]

If the enclosing lambda is removed, the code compiles on all three compilers.

Am I doing something wrong or unsupported, or is just a MSVC bug?

like image 525
jcai Avatar asked May 16 '18 13:05

jcai


1 Answers

This is an MSVC bug. Please file a bug report.

The rule, from [stmt.if]/2, is:

During the instantiation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.

During the instantiation of f<Z>, when we instantiate the condition we get true. That is not value-dependent, so the discard substatement (the one where we do z()) is not instantiated. It's only the instantiation of z() that leads to the error - and it should not be happening.

like image 56
Barry Avatar answered Oct 11 '22 12:10

Barry