简体   繁体   中英

Is it allowed to return a non-literal type from a constexpr function?

struct Outer
{
    explicit constexpr Outer(int ii) : n(ii) {}
    explicit constexpr Outer(double dd) : n(dd) {}

    explicit constexpr Outer(double*) : Outer(3.1415926) {}
    explicit constexpr Outer(int*): Outer(42) {}

    template <typename R>
    static
    constexpr
    Outer meow(R* r = nullptr) { return Outer(r); }

    int    as_i() const { return n.i; }
    double as_d() const { return n.d; }

    union Inner
    {
        int i;
        double d;

        constexpr Inner(int ii) : i(ii) {}
        constexpr Inner(double dd) : d(dd) {}
        ~Inner () {}; // non-trivial destructor

    };

    Inner n;
};

//#include <type_traits>
//static_assert(std::is_literal_type_v<Outer>); // failed by both GCC and clang

int main(int argc, char**)
{
    auto const o = Outer::meow(&argc);
    return o.as_i();
}

The above code is compiled by GCC 12.1 but rejected by clang 14.0.0

https://godbolt.org/z/o6Tvrrdsv

clang (correctly, in my opinion) complains that

<source>:12:11: error: constexpr function's return type 'Outer' is not a literal type
    Outer meow(R* r = nullptr) { return Outer(r); }
          ^
<source>:28:11: note: 'Outer' is not literal because it has data member 'n' of non-literal type 'Outer::Inner'
    Inner n;
          ^
<source>:36:24: error: no matching function for call to 'meow'
    auto const o = Outer::meow(&argc);
                   ^~~~~~~~~~~
<source>:12:11: note: candidate template ignored: substitution failure [with R = int]
    Outer meow(R* r = nullptr) { return Outer(r); }
          ^

Even though o is merely const, not constexpr , shouldn't this be an error? meow is trying to do something which shouoldn't be allowed.

(If I make o into constexpr , then GCC complains that Outer has a non-trivial destructor.)

Yes, the return type of a constexpr function must be a literal type and Outer is not. If a function definition doesn't satisfy the constexpr requirements, the program would be ill-formed.

However, you have a function template here. constexpr on a function template is allowed as long as there is at least one specialization which satisfies the requirements of a constexpr function. However, if this requirement is not fulfilled, the program isn't ill-formed . It is ill-formed, no diagnostic required (IFNDR).

There is no specialization here satisfying the requirements because you always have the Outer return type and so the program is IFNDR.

Both compilers are correct. They do not need to diagnose that the program is ill-formed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM