23

constexpr functions are not supposed to contain:

A definition of a variable of non-literal type

But in this answer a lambda is defined in one: https://stackoverflow.com/a/41616651/2642059

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    return [&]() {
        decltype(std::div(quot, rem)) result;
        result.quot = quot;
        result.rem = rem;
        return result;
    }();
}

and in my comment I define a div_t in one: How can I Initialize a div_t Object?

template <typename T>
constexpr decltype(div(T{}, T{})) make_div(const T quot, const T rem)
{
    decltype(div(T{}, T{})) x{};
    x.quot = quot;
    x.rem = rem;
    return x;
}

Exactly what is meant by the prohibition of the "definition of a variable of non-literal type"?

Visual Studio 2015 won't allow my definition of a div_t but I find it nonsensical that it would be allowable to just wrap such illegitimate behavior in a lambda and execute it. I'd like to know which if either of the compilers are behaving correctly with respect to the div_t definition.

9
  • 2
    What version of the C++ language? The requirements were relaxed quite a bit from 2011. Commented Jan 12, 2017 at 16:45
  • @rubenvb Good question, I've edited. But C++14. Commented Jan 12, 2017 at 16:50
  • 4
    A lambda expression is a expression, not a variable definition. But until C++17, a lambda expression cannot appear in a constant expression. Indeed, when the context requires a constant expression, MSVC will complain. Commented Jan 12, 2017 at 16:57
  • @cpplearner So my (the first) example only compiles as the constexpr function is evaluated as const function? In my opinion the second example should not compile by definition. Commented Jan 12, 2017 at 17:12
  • 3
    I don't think VS2015 supports C++14 extended constexpr. That explains your second function template since in C++11 constexpr functions are basically limited to a single return statement; it has nothing to do with "non-literal type" (and div_t is a literal type). The first one is ill-formed NDR pre-C++17. Commented Jan 12, 2017 at 21:19

1 Answer 1

29

It's virtually guaranteed that if there's a discrepancy gcc has the correct behavior, because Visual Studio 2015 doesn't support 's extension of constexpr: https://msdn.microsoft.com/en-us/library/hh567368.aspx#C-14-Core-Language-Features

C++11 constexpr functions

The function body can only contain:

  • null statements (plain semicolons)
  • static_assert declarations
  • typedef declarations and alias declarations that do not define classes or enumerations
  • using declarations
  • using directives
  • exactly one return statement

So cannot tolerate the definition of decltype(div(T{}, T{})) x{}. It would however be acceptable to roll the ternary suggested here in a constexpr function to achieve the same results:

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    using foo = decltype(div(T{}, T{}));
                         
    return foo{1, 0}.quot != 0 ? foo{quot, rem} : foo{rem, quot};
}

Live Example

C++14 constexpr functions

The function body may contain anything but:

  • an asm declaration
  • a goto statement
  • a statement with a label other than case and default
  • a try-block
  • a definition of a variable of non-literal type
  • a definition of a variable of static or thread storage duration
  • a definition of a variable for which no initialization is performed

Where a "Literal Type" is defined here, specifically for objects though, they may be aggregate types with a trivial destructor. So div_t definitely qualifies. Thus , and by extension gcc, can tolerate the definition of decltype(div(T{}, T{})) x{}.

C++17 constexpr functions

C++17 added support for closure types to the definition of "Literal Type", so I find it strange that both gcc and Visual Studio support the use of the lambda in the return statement. I guess that's either forward looking support or the compiler chose to inline the lambda. In either case I don't think that it qualifies as a constexpr function.

[Source]

Sign up to request clarification or add additional context in comments.

2 Comments

@jnoathan_mee "The function body may contain anything but: ..." , we cannot call non-constexpr function in the body, right?
@camino Correct, the result of this function must be calculable at compile-time, thus functions or parameters which cannot satisfy this requirement are not acceptable. That point isn't clearly documented though is it :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.