Date: Fri, 22 Sep 2023 13:26:59 -0600
Meant to say "auto &gammaClone = clone.values<1>;" and a bunch of other
errors, but I think the example is otherwise clear.
On Fri, Sep 22, 2023 at 12:50 PM Chris Gary <cgary512_at_[hidden]> wrote:
> 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.
>>>
>>
errors, but I think the example is otherwise clear.
On Fri, Sep 22, 2023 at 12:50 PM Chris Gary <cgary512_at_[hidden]> wrote:
> 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.
>>>
>>
Received on 2023-09-22 19:27:12