Why is this constexpr rvalue constructor called at runtime?

Why does the following code consider using class A as a constexpr for the first two cases, but not the third case? I tried this with different gcc versions from 4.9 to 7.1 and experienced the same behavior every time. What am I missing here?

template <std::size_t N> struct B{};

class A
{
public:
    constexpr A(std::size_t value):value_(value){}
    std::size_t const value_;
};


std::int32_t main
(
    std::int32_t,
    char const **
)
{
    A a(1);           // expected - constructor not invoked at run time
    B<A(1).value_> b; // expected - compiles so clearly constexpr
    A(1);             // *** unexpected *** - invokes the constructor at run time, why?
    return 0;
}

      

updated with more detailed example

template <std::size_t N> 
struct B
{
    constexpr std::size_t dont_optimize_me_out
    (
    )
    {
        return 0;
    }
};


constexpr std::size_t some_hash
(
    char const *,
    std::size_t
)
{
    return 0;
}


class hashed_id
{
public:

    template <std::size_t N>
    constexpr hashed_id
    (
        char const (&input)[N]
    ):
        value_(some_hash(input, N - 1))
    {
    }

    constexpr hashed_id
    (
        std::size_t value
    ):
        value_(value)
    {
    }

    constexpr std::size_t get_value
    (
    )
    {
        return value_;
    }

private:

    std::size_t const value_;
};


class A
{
public:

    constexpr A
    (
        hashed_id id
    ):
        id_(id)
    {
    }

    constexpr hashed_id get_id
    (
    )
    {
        return id_;
    }

    constexpr std::size_t dont_optimize_me_out
    (
    )
    {
        return id_.get_value();
    }

private:

    hashed_id const id_;
};


int main
(
    int,
    char const **
)
{
    std::size_t k = 0;

    A a("foo"); // expected - constructor not invoked at run time
    k += a.dont_optimize_me_out();

    B<A("foo").dont_optimize_me_out()> b; // expected - compiles so clearly constexpr
    k += b.dont_optimize_me_out();

    k += A("foo").dont_optimize_me_out(); // *** unexpected *** - invokes the constructor (and hash function) at run time, why?

    std::cout << k << std::endl;
    return 0;
}

      

+3


source to share





All Articles