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.
It's virtually guaranteed that if there's a discrepancy gcc has the correct behavior, because Visual Studio 2015 doesn't support c++14's extension of constexpr: https://msdn.microsoft.com/en-us/library/hh567368.aspx#C-14-Core-Language-Features
constexpr functionsThe function body can only contain:
- null statements (plain semicolons)
 static_assertdeclarationstypedefdeclarations and alias declarations that do not define classes or enumerationsusingdeclarationsusingdirectives- exactly one
 returnstatement
So c++11 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
constexpr functionsThe 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 c++14, and by extension gcc, can tolerate the definition of decltype(div(T{}, T{})) x{}.
constexpr functionsC++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 c++14 constexpr function.
[Source]
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