constexpr all the things
Reference:cppcon2017 constexpr all the things
constexpr specifier
Constant expressions
std::variant
digress:
User-defined literals (From c++11 faq)
A literal operator can request to get its (preceding) literal passed ``cooked''
(with the value it would have had if the new suffix hadn't been defined) or ``uncooked'' (as a string).
constexpr complex<double> operator "" i(long double d) // imaginary literal
{
return {0,d}; // complex is a literal type
}
std::string operator""s (const char* p, size_t n) // std::string literal
{
return string(p,n); // requires free store allocation
}
To get an ``uncooked'' string, simply request a single const char* argument:
Bignum operator"" x(const char* p)
{
return Bignum(p);
}
void f(Bignum);
f(1234567890123456789012345678901234567890x);
There are four kinds of literals that can be suffixed to make a user-defined literal
- integer literal
accepted by a literal operator taking a single unsigned long long or const char* argument. - floating point literal
accepted by a literal operator taking a single long double or const char* argument. - string literal
accepted by a literal operator taking a pair of (const char*, size_t) arguments. - character literal
accepted by a literal operator taking a single char argument.
so different uses could easily clash. Use namespaces to prevent clashes:
namespace Numerics {
// ...
class Bignum { /* ... */ };
namespace literals {
operator"" X(char const*);
}
}
using namespace Numerics::literals;
Benefit of constexpr
- Runtime efficiency
- Clearer code, fewer magic numbers
- Less cross-platform pain
Requirements for compile time types
- constexpr constructor
- std::is_trivially_destructible
constexpr allocator
template <class T, size_t Size>
struct ConstexprAllocator {
typedef T value_type;
consstexpr ConstexprAllocator(/*ctor args*/);
template <class U>
constexpr ConstexprAllocator(const ConstexprAllocator<U>& other);
constexpr T* allocate(std::size_t n);
constexpr void deallocate(T* p, std::size_t n);
std::array<std::pair<bool, value_type>, Size> data; // bool for free flag
};
Currently any type with a non-trivial destructor cannot be used in constexpr context.
Reason:
Run-time adjusting this pointer.
Solution to the constexpr destructor problem
struct Container {
~Container() {
// this proposal allows for an empty destructor to be allowed
if constexpr(something) {
// do something
}
}
};
// OR
struct Container {
~Container() {
// but why not treat it like any other constexpr code?
// allow it as long as only constexpr allowed actions
// happen at compile time?
if (extra_data) {
delete [] extra_data;
}
}
};
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.