2

I'm trying to make an aligned variant type that uses std::aligned_storage to hold the data. Is there a way to construct an object in place in a constexpr way? I read you can't do constexpr placement new.

#include <iostream>
#include <string>


struct foo
{
    foo(std::string a, float b)
    : bar1(a), bar2(b)
    {}

    std::string bar1;
    float bar2;
};


struct aligned_foo
{
    template<typename... Args>
    aligned_foo(Args&&... args) 
    {
        //How to constexpr construct foo?
        data_ptr = ::new((void*)::std::addressof(storage)) foo(std::forward<Args>(args)...);
    }

    std::aligned_storage<sizeof(foo)> storage;
    foo* data_ptr;
};


int main()
{
    aligned_foo("Hello", 0.5);
}
Andreas Loanjoe
  • 2,205
  • 10
  • 26
  • `std::string` doesn't have a `constexpr` constructor, so unlikely. – Bo Persson Oct 28 '17 at 11:15
  • 2
    **Short answer:** No. **Long answer:** One of the possible reasons: The lifetime of an object of a class type begins when its constructor has completed. For `constexpr` contexts, the only sane way to manage such lifetimes is with objects of *automatic storage duration* or *static storage duration* - because the compiler can reason about these lifetimes easily. Maybe when our compilers get as capable as Rust, we can do better in this regard – WhiZTiM Oct 28 '17 at 11:19

1 Answers1

1

No. One of the long list of expressions that can't appear in a constant expression is a new-expression.

The only way to implement a variant and have it be constexpr-friendly is through the use of a union. Although, even with a union, you still wouldn't be able to have a constexpr-friendly variant that can contain a foo since it's not a literal type (by way of it having a non-trivial destructor, by way of std::string having a non-trivial destructor).

Barry
  • 286,269
  • 29
  • 621
  • 977