Date: Fri, 22 Sep 2023 12:50:35 -0600
Other rough ideas I've had since c++11:
`template< typename ...ValuesT >
struct Mirror
{
// First-class tuples.
ValuesT ...values;
Mirror( cosnt ValuesT &..values )
: values{ values }... // <- Note '...' _after_ the IL
{}
};
struct MiscData
{
unsigned passes;
float gamma;
int example;
double value;
};
void DoThings( unsigned a, float b, int c, double d );
void Fn()
{
MiscData data = GetFromElsewhere();
// Unpack public type members of MiscData in declaration order.
// Unpack public value members of a MiscData instance in the same order.
Mirror< MiscData... > clone{ data... };
// Use some kind of indexing mechanism.
// I've opted for "<index>", since it seems unambiguous next to a value
member.
auto &gammaClone = clone.values<0>;
// With CTAD (this is already valid):
Mirror clone2{ data... };
// Same thing as with "data", just unpack public members in declaration
order.
DoThings( clone2... );
}
template< typename Arg_t >
Arg_t Flatten( Arg_t arg )
{ return arg; }
// Should produce a single-level Mirror<>
template< typename Arg_t, typename ...Args_t >
auto Flatten( Arg_t arg, Args_t ...args )
{
return Mirror{ arg, Flatten( args )... };
}`
I imagine there could be some places where this is ambiguous.
I think the thread ought to be re-started as "Unpack anything with ..." or
"Nested ellipses".
On Thu, Sep 21, 2023 at 2:21 PM Chris Gary <cgary512_at_[hidden]> wrote:
> Maybe that information can be hoisted into the function's metadata,
>> inducing a set of functions based on their parameters?
>>
>> Admittedly, the binding criteria are complicated.
>>
>> More concretely (somewhat),
>>
>> read this:
>> `constexpr auto q = 123456.789_qq;`
>>
>> like this:
>> `constexpr auto q = operator ""_qq( "123456.789", 10u );`
>>
>> or, closer to what I mean:
>>
>> `constexpr auto q = operator ""_qq( "123456.789" );`
>>
>> where the definition is:
>>
>> `template< std::size_t size_ >
>> constexpr mp_rational operator ""_qq( const char (&lit)[size_] )
>> requires( std::is_constant_evaluated() ? matches_std_numeric_literal( lit
>> ) : true )
>> {
>> if( std::is_constant_evaluated() )
>> {
>> using MQQ = materialize_qq_from_static_literal< lit... >;
>> }
>> else
>> {
>> if( ! matches_std_numeric_literal( lit ) )
>> {
>> throw std::invalid_argument{};
>> }
>>
>> // etc...
>> }
>> }`
>>
>> loosely speaking.
>>
>> Template instantiations and static function invocations given known
>> parameters can be viewed uniformly as unique "types". This is already
>> known, since constexpr functions can be used to instantiate templates (e.g.
>> a non-type parameter is identified by its constructor arguments).
>>
>> So, an alternative assuming something like constexpr static would work
>> intuitively:
>>
>> `template< typename CodeUnitT, std::size_t size_ >
>> constexpr mp_rational operator ""_qq( const CodeUnitT (&lit)[size_] )
>> requires( std::is_constant_evaluated() ? matches_std_numeric_literal( lit
>> ) : true )
>> {
>> // At compile-time: The requires clause is evaluated, raising errors
>> wherever
>> // the data can be examined directly.
>> //
>> // At runtime: Throws an exception if lit violates whats in the
>> requires() clause above.
>> return materialize_qq_from_static_literal_as_fn( lit ).bind();
>> }`
>>
>> Reflecting on this, what I'm really after is just materializing ordinary
>> data from compile time into static data...
>>
>> To my original point, being able to expand arrays into other arrays (or
>> function parameter lists) seems obvious to me.
>>
>
`template< typename ...ValuesT >
struct Mirror
{
// First-class tuples.
ValuesT ...values;
Mirror( cosnt ValuesT &..values )
: values{ values }... // <- Note '...' _after_ the IL
{}
};
struct MiscData
{
unsigned passes;
float gamma;
int example;
double value;
};
void DoThings( unsigned a, float b, int c, double d );
void Fn()
{
MiscData data = GetFromElsewhere();
// Unpack public type members of MiscData in declaration order.
// Unpack public value members of a MiscData instance in the same order.
Mirror< MiscData... > clone{ data... };
// Use some kind of indexing mechanism.
// I've opted for "<index>", since it seems unambiguous next to a value
member.
auto &gammaClone = clone.values<0>;
// With CTAD (this is already valid):
Mirror clone2{ data... };
// Same thing as with "data", just unpack public members in declaration
order.
DoThings( clone2... );
}
template< typename Arg_t >
Arg_t Flatten( Arg_t arg )
{ return arg; }
// Should produce a single-level Mirror<>
template< typename Arg_t, typename ...Args_t >
auto Flatten( Arg_t arg, Args_t ...args )
{
return Mirror{ arg, Flatten( args )... };
}`
I imagine there could be some places where this is ambiguous.
I think the thread ought to be re-started as "Unpack anything with ..." or
"Nested ellipses".
On Thu, Sep 21, 2023 at 2:21 PM Chris Gary <cgary512_at_[hidden]> wrote:
> Maybe that information can be hoisted into the function's metadata,
>> inducing a set of functions based on their parameters?
>>
>> Admittedly, the binding criteria are complicated.
>>
>> More concretely (somewhat),
>>
>> read this:
>> `constexpr auto q = 123456.789_qq;`
>>
>> like this:
>> `constexpr auto q = operator ""_qq( "123456.789", 10u );`
>>
>> or, closer to what I mean:
>>
>> `constexpr auto q = operator ""_qq( "123456.789" );`
>>
>> where the definition is:
>>
>> `template< std::size_t size_ >
>> constexpr mp_rational operator ""_qq( const char (&lit)[size_] )
>> requires( std::is_constant_evaluated() ? matches_std_numeric_literal( lit
>> ) : true )
>> {
>> if( std::is_constant_evaluated() )
>> {
>> using MQQ = materialize_qq_from_static_literal< lit... >;
>> }
>> else
>> {
>> if( ! matches_std_numeric_literal( lit ) )
>> {
>> throw std::invalid_argument{};
>> }
>>
>> // etc...
>> }
>> }`
>>
>> loosely speaking.
>>
>> Template instantiations and static function invocations given known
>> parameters can be viewed uniformly as unique "types". This is already
>> known, since constexpr functions can be used to instantiate templates (e.g.
>> a non-type parameter is identified by its constructor arguments).
>>
>> So, an alternative assuming something like constexpr static would work
>> intuitively:
>>
>> `template< typename CodeUnitT, std::size_t size_ >
>> constexpr mp_rational operator ""_qq( const CodeUnitT (&lit)[size_] )
>> requires( std::is_constant_evaluated() ? matches_std_numeric_literal( lit
>> ) : true )
>> {
>> // At compile-time: The requires clause is evaluated, raising errors
>> wherever
>> // the data can be examined directly.
>> //
>> // At runtime: Throws an exception if lit violates whats in the
>> requires() clause above.
>> return materialize_qq_from_static_literal_as_fn( lit ).bind();
>> }`
>>
>> Reflecting on this, what I'm really after is just materializing ordinary
>> data from compile time into static data...
>>
>> To my original point, being able to expand arrays into other arrays (or
>> function parameter lists) seems obvious to me.
>>
>
Received on 2023-09-22 18:50:48