Date: Sat, 03 Aug 2024 02:16:24 +0400
Your solution requires at compile time information that is only available at runtime.I don't understand what runtime data you are referring to.In the algorithm explained before. All the data, that the compiler's pre-pass is manipulating, are compile time data.At the level of a translation unit. A function with orthogonal template parameters (foo<T>)cannot exist unless you instantiate it.
Add to that, the function is tagged as per the algorithm, so it is prone to record the types it was instantiated for.But as an optimization, the compiler will not record the list of orthogonal template parameters unless it sees that some variable is using it, otherwise no need to generate any code.The compiler confirmed that by the usage of the effdecltype operator inside the template argument of the vector in the example.Every time you instantiate foo with a type, you have to write it explicitly in the source code.foo<int>, foo<double>...etcNext to that, the address of a function is a constexpr value, you can use it as a non-type template parameter.So as a summary, the list of orthogonal template parameters is fetchable from the source code, and the address of the instances is constexpr value.These are the ingredients to make the algorithm work.
Even if the compiler could trace data across any type of data container (which it won't),It doesn't need to, because the information needed is the orthogonal template parameters not the number of elements in the container.You can have 100 element of type foo<int>, but the list of orthogonal template parameters is only { int }It's like you are counting how many instances of foo<T> you have in that translation unit. datapoints in container could take the form of any possible combination on any position and be influenced to translation units not visible at compile
time. But for your solution to work it requires a fix layout (which in practice doesn't happen) and perfect observability.
This is not a problem that needs to be solved, it's just how things work.Let me reiterate.Look at this snippet:vec.push_back(&foo<int>);int random;cin >> random;while(random - -) vec.push_back(&foo<char>);cin >> random;random = min(random, vec.size());while(random - -) vec.pop_back();As you can see, i cannot tell nor track the vector size. But it is irrelevant, because i have only two function pointer => { int, char }And by consequence my switch statment will contain only two cases:case &foo<int>:return __Xic_foo_eff_{ &foo<int>, int(0) };case &foo<char>:return __Xic_foo_eff_{ &foo<char>, char(0) };The two case lables are constexpr values known at compile time.
You cannot resolve this problem without appending extra data to containers that is used to inform about the nature of the data. And you cannot solve this without a runtime check and control flow to browse for the right handler.
This is a problem of distinguishability and computability, it is not something you can solve, it's a consequence of math as described by Shannon.
That's why std:any has additional data related to runtime type information, and that's why it always needs some form of selection or hash table or equivalent.Well, i just proved to you that i don't need that data, and that this approach is plausibly more effecient and safe.Let's try to stretch it more, shall we?
The way it's already done is already how this problem should be solved, no new feature necessary. What you are proposing requires the suspension of the laws of physics.
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 9:44:09 PM
To: Tiago Freire <tmiguelf_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
And also unimplementable...
But you don't have to take my word for it, you can try it yourself.
But ... that's the whole purpose of this thread.
Putting down an idea in form of a paper, or an algorithm and tackle any contradiction it raise untill we hit the wall or we make it through.
And we have just started agreeing about the core idea. Which is
Adding an operator that does overload dispatch and code generation...etc
If it is not implementable, then point where, i will work on it...
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of organicoman via Std-Proposals <std-proposals_at_[hidden]>
Sent: Friday, August 2, 2024 9:15:36 PM
To: organicoman via Std-Proposals <std-proposals_at_[hidden]>
Cc: organicoman <organicoman_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
Hello Gašper,
Since participants are starting to get what I am talking about, then allow me to answer your pending question.
This is what you've said in previous post.
There is another fundamental misunderstanding here.
The feature calls to "record all the orthogonal template parameters".
While that's not what that word means, I think regardless it's asking for global enumeration. C++ has a separate linking model. All the types/functions are not known within a single unit. The xunion is impossible
to compute.
This is a sister problem to what Jason is highlighting.
When i was describing my algorithm, i left a big X mark, hoping that someone will ask me, if people were attentive.
Line:
4-b-
switch
*.....
* inside function body: goto X
Then I left a hint at the bottom of the post in a form of code comment
double var2 = *reinterpret_cast<double*>
((reinterpret_cast<char*>(&(useType()))+sizeof(int));
// int since __X_index is int. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^
The __X_index is not of type
int but of type
void*, the unnamed struct that the compiler generate becomes:
struct __Xidfc_foo_eff
{
void* __X_index;
union
{ int __Xi; double __Xd ; float __Xf; char __Xc };
};
Since the compiler tagged
useType function, as described by the algorithm, then after finishing recording the orthogonal template parameters, it replaces the body with the following.
auto useType(effdecltype(foo) f)
{
f();
switch(f)
{
case &f<int>: //<- the pointer value
return __Xidfc_foo_eff{(void*) &f<int>, int(0)};
case &f<double>:
return __Xidfc_foo_eff{(void*) &f<double>, double(0)};
case &f<float>:
return __Xidfc_foo_eff{(void*) &f<float>, float(0)};
case &f<char>:
return __Xidfc_foo_eff{(void*) &f<char>, char(0)};
}
}
Pointers are comparable for equality.
As you can see, you can capture the xunion.... right? There is no fundamental misunderstanding ...
Plus everything is done by the compiler, there is no global map, no find algorithm, no type hashs, no type erasure (heap allocation), no manual intervention. All is automated at compile-time.
Add to that, the function is tagged as per the algorithm, so it is prone to record the types it was instantiated for.But as an optimization, the compiler will not record the list of orthogonal template parameters unless it sees that some variable is using it, otherwise no need to generate any code.The compiler confirmed that by the usage of the effdecltype operator inside the template argument of the vector in the example.Every time you instantiate foo with a type, you have to write it explicitly in the source code.foo<int>, foo<double>...etcNext to that, the address of a function is a constexpr value, you can use it as a non-type template parameter.So as a summary, the list of orthogonal template parameters is fetchable from the source code, and the address of the instances is constexpr value.These are the ingredients to make the algorithm work.
Even if the compiler could trace data across any type of data container (which it won't),It doesn't need to, because the information needed is the orthogonal template parameters not the number of elements in the container.You can have 100 element of type foo<int>, but the list of orthogonal template parameters is only { int }It's like you are counting how many instances of foo<T> you have in that translation unit. datapoints in container could take the form of any possible combination on any position and be influenced to translation units not visible at compile
time. But for your solution to work it requires a fix layout (which in practice doesn't happen) and perfect observability.
This is not a problem that needs to be solved, it's just how things work.Let me reiterate.Look at this snippet:vec.push_back(&foo<int>);int random;cin >> random;while(random - -) vec.push_back(&foo<char>);cin >> random;random = min(random, vec.size());while(random - -) vec.pop_back();As you can see, i cannot tell nor track the vector size. But it is irrelevant, because i have only two function pointer => { int, char }And by consequence my switch statment will contain only two cases:case &foo<int>:return __Xic_foo_eff_{ &foo<int>, int(0) };case &foo<char>:return __Xic_foo_eff_{ &foo<char>, char(0) };The two case lables are constexpr values known at compile time.
You cannot resolve this problem without appending extra data to containers that is used to inform about the nature of the data. And you cannot solve this without a runtime check and control flow to browse for the right handler.
This is a problem of distinguishability and computability, it is not something you can solve, it's a consequence of math as described by Shannon.
That's why std:any has additional data related to runtime type information, and that's why it always needs some form of selection or hash table or equivalent.Well, i just proved to you that i don't need that data, and that this approach is plausibly more effecient and safe.Let's try to stretch it more, shall we?
The way it's already done is already how this problem should be solved, no new feature necessary. What you are proposing requires the suspension of the laws of physics.
From: organicoman <organicoman_at_[hidden]>
Sent: Friday, August 2, 2024 9:44:09 PM
To: Tiago Freire <tmiguelf_at_[hidden]>; std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
And also unimplementable...
But you don't have to take my word for it, you can try it yourself.
But ... that's the whole purpose of this thread.
Putting down an idea in form of a paper, or an algorithm and tackle any contradiction it raise untill we hit the wall or we make it through.
And we have just started agreeing about the core idea. Which is
Adding an operator that does overload dispatch and code generation...etc
If it is not implementable, then point where, i will work on it...
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of organicoman via Std-Proposals <std-proposals_at_[hidden]>
Sent: Friday, August 2, 2024 9:15:36 PM
To: organicoman via Std-Proposals <std-proposals_at_[hidden]>
Cc: organicoman <organicoman_at_[hidden]>
Subject: Re: [std-proposals] Function overload set type information loss
Hello Gašper,
Since participants are starting to get what I am talking about, then allow me to answer your pending question.
This is what you've said in previous post.
There is another fundamental misunderstanding here.
The feature calls to "record all the orthogonal template parameters".
While that's not what that word means, I think regardless it's asking for global enumeration. C++ has a separate linking model. All the types/functions are not known within a single unit. The xunion is impossible
to compute.
This is a sister problem to what Jason is highlighting.
When i was describing my algorithm, i left a big X mark, hoping that someone will ask me, if people were attentive.
Line:
4-b-
switch
*.....
* inside function body: goto X
Then I left a hint at the bottom of the post in a form of code comment
double var2 = *reinterpret_cast<double*>
((reinterpret_cast<char*>(&(useType()))+sizeof(int));
// int since __X_index is int. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^
The __X_index is not of type
int but of type
void*, the unnamed struct that the compiler generate becomes:
struct __Xidfc_foo_eff
{
void* __X_index;
union
{ int __Xi; double __Xd ; float __Xf; char __Xc };
};
Since the compiler tagged
useType function, as described by the algorithm, then after finishing recording the orthogonal template parameters, it replaces the body with the following.
auto useType(effdecltype(foo) f)
{
f();
switch(f)
{
case &f<int>: //<- the pointer value
return __Xidfc_foo_eff{(void*) &f<int>, int(0)};
case &f<double>:
return __Xidfc_foo_eff{(void*) &f<double>, double(0)};
case &f<float>:
return __Xidfc_foo_eff{(void*) &f<float>, float(0)};
case &f<char>:
return __Xidfc_foo_eff{(void*) &f<char>, char(0)};
}
}
Pointers are comparable for equality.
As you can see, you can capture the xunion.... right? There is no fundamental misunderstanding ...
Plus everything is done by the compiler, there is no global map, no find algorithm, no type hashs, no type erasure (heap allocation), no manual intervention. All is automated at compile-time.
Received on 2024-08-02 22:16:43