Date: Mon, 21 Jul 2025 19:16:20 +0000
I am sorry to send an email again so soon, but the formatting was not transferred through.
Here is a link to a PDF of the suggestion.
https://drive.google.com/file/d/1ryFSNHknJbeXtYiU6qfWXsW5dK0NrqGn/view?usp=sharing
Attached is the same file except sent through email.
[https://res.public.onecdn.static.microsoft/assets/mail/file-icon/png/pdf_16x16.png]c++ proposal.pdf<https://1drv.ms/b/s!AtQk6qXtpaa5geGXcqPcgaIp0reHnPM>
________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of std-proposals-request_at_[hidden] <std-proposals-request_at_[hidden]>
Sent: Monday, July 21, 2025 2:31 PM
To: std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Std-Proposals Digest, Vol 76, Issue 59
Send Std-Proposals mailing list submissions to
std-proposals_at_[hidden]
To subscribe or unsubscribe via the World Wide Web, visit
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.isocpp.org%2Fmailman%2Flistinfo.cgi%2Fstd-proposals&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218844647%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=OsFuQjKU3VeOFlOVuUaYJ8EbXx6Bq1%2Bp5bWE%2FxzRSMw%3D&reserved=0<https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals>
or, via email, send a message with subject or body 'help' to
std-proposals-request_at_[hidden]
You can reach the person managing the list at
std-proposals-owner_at_[hidden]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Std-Proposals digest..."
Today's Topics:
1. Non-Member Conversion Operator Overload (Elijah Clark)
----------------------------------------------------------------------
Message: 1
Date: Mon, 21 Jul 2025 18:31:42 +0000
From: Elijah Clark <Stamparkour_at_[hidden]>
To: "std-proposals_at_[hidden]" <std-proposals_at_[hidden]>
Subject: [std-proposals] Non-Member Conversion Operator Overload
Message-ID:
<EA2P223MB116309F885B9EFFB89E3BFEAB75DA_at_[hidden]>
Content-Type: text/plain; charset="windows-1252"
Non-Member Conversion Operator Overload
Problem
With implementing conversion (typecast, static_cast) operator overloading of a partial template specialization class, the conversion only applies for the primary definition not any of the partial specialization class definitions.
I might be missing something within C++ that could solve my issue, I am also working in Visual Studio 2022, MSVC ?Preview - Features from the Latest C++ Working Draft (/std:c++latest)?, so please correct me if anything is wrong. I am sorry if this has been brought up before, but I could not find anything related to the topic at discussion.
My Project Requirements
I am currently working on a compile-time linear algebra project. For Vectors, I need to be able to make an N-Dimensional arbitrary Vector, with the most common vectors allowing for the usual ?V.x, V.y, V.z, V.w? member attributes.
Current Solution
Currently in present C++, you need to add a macro for (or a copy of) all the necessary conversion operator overloads. This solution is not easily maintainable for larger projects and pollutes the macro space with possibly unneeded macros. Furthermore, this solution is cumbersome and not beginner friendly as one would think of the alternative solutions presented below.
Based on my understanding of the current direction of C++ and its modules, C++ is trying to remove the need for macros and all the clutter. All in all, I feel that this should not be the de facto solution.
#define STAMP_MATH_VECTOR_TYPECAST_GENERIC \
Vector() noexcept : V({}) {} \
Vector(T x) noexcept { \
for (size_t i = 0; i < D; i++) V[i] = x; \
} \
template<typename T1, size_t D1> explicit operator Vector<T1, D1>() const noexcept { \
Vector<T1, D1> o; \
for (size_t i = 0; i < D1; ++i) \
o.V[i] = (i < D ? static_cast<T1>(V[i]) : 0); \
return o; \
} \
explicit operator const T* () const noexcept { return &V; } \
explicit operator T* () noexcept { return &V; } \
explicit operator bool() const noexcept { \
for (size_t i = 0; i < D; ++i) if(!V[i]) return false; \
return true; \
}
template<typename T, size_t D>
struct Vector {
T V[D];
STAMP_MATH_VECTOR_TYPECAST_GENERIC;
};
template <typename T>
struct Vector<T, 2> final {
constexpr static size_t D = 2;
union {
T V[2];
struct {
T x;
T y;
};
};
Vector(T x, T y) noexcept : x(x), y(y) {}
STAMP_MATH_VECTOR_TYPECAST_GENERIC;
};
Excerpt A - from project.
Alternate Solutions
In this section, I will dive into alternate solutions that came to mind after a few days of pondering.
Non-Member Conversion Operator Overload
This solution I feel will be the most supported, or generally the easiest to implement as almost all other operator overloads can be defined outside of the class (ex, implementing your own ?std::cout <<? function).
If we assume that Non-member conversion operator overloading can exist, we get:
template<typename T, size_t D>
struct Vector {
T V[D];
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
};
template <typename T>
struct Vector<T, 2> final {
constexpr static size_t D = 2;
union {
T V[2];
struct {
T x;
T y;
};
};
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
Vector(T x, T y) noexcept : x(x), y(y) {}
};
template<typename T, size_t D, typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i) o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
template<typename T, size_t D>
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
template<typename T, size_t D>
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
template<typename T, size_t D>
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
Excerpt B - for showcasing nonmember conversion overloading.
This implementation would behave the same as the code in Excerpt A.
Although this code is longer than my original example, I feel that this scales better and is easier to read. Let?s say we need Vector implementations all the way to Dimension 7, with members from X to W, A, B , C: not having to copy the same conversion operator will lead to cleaner code.
One potential rule that could be added is requiring the explicit keyword on all non-member conversion operators overloads, but this would add excessive limitation.
How would this affect existing code?
Yes, letting the user be able to create conversion operators willy-nilly could break projects that rely on a class not converting to different types, but I feel this could benefit way more than break. Furthermore, why would a user start adding typecasting randomly in a project? And couldn?t you do this by using member conversion operator overloading?
What would happen if this nonmember declaration already exists as a member operator overload?
I believe this should have similar implementation to other nonmember operator overloading and cause compilation errors.
Why hasn't this been implemented before?
Based on some research, I found only a Stack Overflow thread<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F34056443%2Fwhy-cant-i-overload-c-conversion-operators-outside-a-class-as-a-non-member-f&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218859586%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=eg9IL2t4NyGxbZLhXKAYRjIs%2FUs1LpAjRuAyphG9xU0%3D&reserved=0<https://stackoverflow.com/questions/34056443/why-cant-i-overload-c-conversion-operators-outside-a-class-as-a-non-member-f>> asking the same question 8 years ago with the answer being summarized as ?no one really cared about feature X enough to fight for it.? They also point out how this could create a lot of confusion for the compiler and reader, but I feel this operator overloading could greatly benefit projects such as the one I presented above.
Does This solve any other problems besides template specialization?
Conversion operator overloading could also solve other templated typecasting greatly simplifying codebases. I have not thought this through but I could come up with something if necessary.
Would this add excesses work for a compiler?
I don?t fully know how this will work, but this implementation should require the same number of conversion candidates as one would just have copy-pasted the conversion operators throughout all classes.
Why not create a separate function to act as a conversion operator?
Although, yes I could do this, the code would be less intuitive on first glance and lead to longer implementations of the vectors.
Vector<float, 2> A;
Vector<int, 4> B;
Auto C = A + ConvertVector<float, 2>(B);
Verse
Vector<float, 2> A;
Vector<int, 4> B;
Auto C = A (Vector<float, 2>)B;
Partial Template Specialization Act Similar to Class Inheritance
This solution would greatly alter existing implementations of partial specialization and so I feel this one will not be accepted, but I will still explore this option.
template<typename T, size_t D>
struct Vector {
T V[D];
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
template<typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i)
o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
};
template <typename T>
struct Vector<T, 2> final {
constexpr static size_t D = 2;
union {
T V[2];
struct {
T x;
T y;
};
};
Vector(T x, T y) noexcept : x(x), y(y) {}
};
Excerpt C ? for showcasing partial template specialization acting as class inheritance
In this example, I am suggesting that each member of the base templated class will be implicitly copied over to all implementations and if any duplicate members arise, the partial specialization member will take precedence. This implementation will act the same way as the above code.
So if you have ?Vector<float, 2> a {}; float* ptr = (float*)a;? the variable a will be defined with the partial specialization and will still have access to the base template members.
Would this break existing code?
Yes, fully. So, I would suggest having some keyword to explicitly tell the compiler that ?hey, this function should be copied to all partial specialization implementations.? Based on my understanding, the ISO committee does not like adding new keywords and so I feel this will be a dealbreaker.
How would members declared inside partial template specialization work?
The only members being copied over are from the original templated class and so no other confusion is present. This limitation I feel is necessary, as partial specialization already is very hard for the compiler to work with.
Why implement this in the C++ standard if it is no niche?
I agree, this suggestion is very specific to this problem, and I can?t imagine any other problems that require this solution.
Get/Set member
By using the getter/setter implementation, the Vector class can be one templated class without any partial specialization but then you would have a function ? such as w() ? that will be defined but will crash for vectors with dimensions 1, 2 or 3. Additionally this would require the parenthesis and would look less tidy. One workaround would be implementing a base Vector class and having child classes.
A solution to the parenthesis clutter could be an attribute which would allow the compiler to see a function name and implicitly call the getter, setter functions.
template<typename T, size_t D>
struct Vector {
T V[D];
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
template<typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i)
o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
};
template <typename T>
struct Vector2 final : Vector<T, 2> {
Vector(T x, T y) noexcept : {
this->x = x; //implicitly calls the setter.
this->y = y;
}
void [[setter]] x(T v) {
V[0] = v;
}
T [[getter]] x() {
return V[0];
}
void [[setter]] y(T v) {
V[1] = v;
}
T [[getter]] y() {
return V[1];
}
};
Excerpt D ? for showcasing getter setter attribute
I haven?t thought this one through, but I do feel C++ would benefit with this a lot more than the other solutions. Furthermore, this only partially solves my issue as I still need the partial template to use a matrix code (see ?Why implement the Vector as a partial template specialization?) and using a parent-child class would greatly increase the vector memory usage for any virtual functions (although possibly not a problem).
Union with ?Greedy/Nongreedy? Members
This is inspired from REGEX .+? , in which would take the least number of characters necessary for the match. By allowing a union to have ?optional? members which would only be accessible once the other members reach a certain size, you could implement the Vector class as:
template<typename T, size_t D>
struct Vector {
union {
T V[D];
struct [[nongreedy]] {
T x, y, z, w, a, b, c;
};
};
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
template<typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i)
o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
};
Excerpt E ? for showcasing nongreedy union
This showcases a possible implementation of a nongreedy attribute in which would only give more members once ?T V[D];? reaches the size equivalent of the struct?s members. This solution is so niche and ?weird? when compared to other C++ features that I feel this solution will not be implemented.
Would this increase compiler complexity greatly?
Yes, that?s why I feel this solution is not the correct direction for the partial template problem.
Overload Dot Operator
This solution takes inspiration from LUA. I fully believe this goes against the spirit of C++ and so I won?t go further.
Potential Questions Unrelated to my suggestion
Why implement the Vector as a partial template specialization?
I have a compile time n*n matrix that uses the vector.
template<Quantity T, size_t Rows, size_t Cols> struct Matrix;
template<Quantity T, size_t Rows>
struct Matrix<T, Rows, 1> {
explicit Matrix(const Vector<T, Rows>& m) noexcept;
};
Excerpt Q1 - from project.
Furthermore, this solution could help other developers working with C++ and needing to go through the headache inducing problem solving.
Why use compile time declaration?
I need compile-time vector and matrix definitions for real time graphics rendering.
Why is this so in-depth for such a small problem?
I feel that having more options will greatly quicken the process of problem solving. Additionally I don?t want to spam this email with alternatives to this one problem.
Definitions of Terms
As I am not completely well versed in C++ terminology, I will add this section to showcase what I mean by some words. This is not meant to be patronizing but to help me better articulate my points.
Member ? Class scope declaration ? variables, functions, etc.
Non-member, nonmember ? namespace or global scope declarations.
Conversion, typecast ? converting between two types. ?static_cast<T2>(T1 value)?
Partial Specialization, partial template specialization ? https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fen.cppreference.com%2Fw%2Fcpp%2Flanguage%2Fpartial_specialization.html&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218868002%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=5zFzVArHDLt1m5gLEjDoVuK1mNr%2F2iDOm94CdzZ2flw%3D&reserved=0<https://en.cppreference.com/w/cpp/language/partial_specialization.html>
This file<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdrive.google.com%2Ffile%2Fd%2F1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm%2Fview%3Fusp%3Dsharing&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218876158%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=n6%2BWjPTrc4WU8IfHkZpB08aEHuWnoEpAu2c%2B2fJyG%2Fc%3D&reserved=0<https://drive.google.com/file/d/1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm/view?usp=sharing>> <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdrive.google.com%2Ffile%2Fd%2F1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm%2Fview%3Fusp%3Dsharing&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218885536%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=Rj8cxrGRenrXy5iIWXy5feyTmrahFrw37Br8DEF3%2BF0%3D&reserved=0<https://drive.google.com/file/d/1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm/view?usp=sharing>> is the code that I have been referencing in "Current Solution".
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdrive.google.com%2Ffile%2Fd%2F1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm%2Fview%3Fusp%3Dsharing&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218897580%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=9Tn7vawPGM9X1xAfm9Ohmoxn9WBZs3jeUvprbh5TxBQ%3D&reserved=0<https://drive.google.com/file/d/1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm/view?usp=sharing>
Please note that this email is mostly a draft and might contain errors.
-------------- next part --------------
HTML attachment scrubbed and removed
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: vector.h
URL: <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.isocpp.org%2Fstd-proposals%2Fattachments%2F20250721%2F7baf2c05%2Fattachment.h&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218905953%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=EHk2njqrthG6qBme20U1EEezleV%2BLafGdKIIjYke0yA%3D&reserved=0<https://lists.isocpp.org/std-proposals/attachments/20250721/7baf2c05/attachment.h>>
------------------------------
Subject: Digest Footer
Std-Proposals mailing list
Std-Proposals_at_[hidden]
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.isocpp.org%2Fmailman%2Flistinfo.cgi%2Fstd-proposals&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218914284%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=P8G2tk47VpJru6N2l3Nx0ISsE2mgojTBZJ90bRU8MQo%3D&reserved=0<https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals>
------------------------------
End of Std-Proposals Digest, Vol 76, Issue 59
*********************************************
Here is a link to a PDF of the suggestion.
https://drive.google.com/file/d/1ryFSNHknJbeXtYiU6qfWXsW5dK0NrqGn/view?usp=sharing
Attached is the same file except sent through email.
[https://res.public.onecdn.static.microsoft/assets/mail/file-icon/png/pdf_16x16.png]c++ proposal.pdf<https://1drv.ms/b/s!AtQk6qXtpaa5geGXcqPcgaIp0reHnPM>
________________________________
From: Std-Proposals <std-proposals-bounces_at_[hidden]> on behalf of std-proposals-request_at_[hidden] <std-proposals-request_at_[hidden]>
Sent: Monday, July 21, 2025 2:31 PM
To: std-proposals_at_[hidden] <std-proposals_at_[hidden]>
Subject: Std-Proposals Digest, Vol 76, Issue 59
Send Std-Proposals mailing list submissions to
std-proposals_at_[hidden]
To subscribe or unsubscribe via the World Wide Web, visit
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.isocpp.org%2Fmailman%2Flistinfo.cgi%2Fstd-proposals&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218844647%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=OsFuQjKU3VeOFlOVuUaYJ8EbXx6Bq1%2Bp5bWE%2FxzRSMw%3D&reserved=0<https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals>
or, via email, send a message with subject or body 'help' to
std-proposals-request_at_[hidden]
You can reach the person managing the list at
std-proposals-owner_at_[hidden]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of Std-Proposals digest..."
Today's Topics:
1. Non-Member Conversion Operator Overload (Elijah Clark)
----------------------------------------------------------------------
Message: 1
Date: Mon, 21 Jul 2025 18:31:42 +0000
From: Elijah Clark <Stamparkour_at_[hidden]>
To: "std-proposals_at_[hidden]" <std-proposals_at_[hidden]>
Subject: [std-proposals] Non-Member Conversion Operator Overload
Message-ID:
<EA2P223MB116309F885B9EFFB89E3BFEAB75DA_at_[hidden]>
Content-Type: text/plain; charset="windows-1252"
Non-Member Conversion Operator Overload
Problem
With implementing conversion (typecast, static_cast) operator overloading of a partial template specialization class, the conversion only applies for the primary definition not any of the partial specialization class definitions.
I might be missing something within C++ that could solve my issue, I am also working in Visual Studio 2022, MSVC ?Preview - Features from the Latest C++ Working Draft (/std:c++latest)?, so please correct me if anything is wrong. I am sorry if this has been brought up before, but I could not find anything related to the topic at discussion.
My Project Requirements
I am currently working on a compile-time linear algebra project. For Vectors, I need to be able to make an N-Dimensional arbitrary Vector, with the most common vectors allowing for the usual ?V.x, V.y, V.z, V.w? member attributes.
Current Solution
Currently in present C++, you need to add a macro for (or a copy of) all the necessary conversion operator overloads. This solution is not easily maintainable for larger projects and pollutes the macro space with possibly unneeded macros. Furthermore, this solution is cumbersome and not beginner friendly as one would think of the alternative solutions presented below.
Based on my understanding of the current direction of C++ and its modules, C++ is trying to remove the need for macros and all the clutter. All in all, I feel that this should not be the de facto solution.
#define STAMP_MATH_VECTOR_TYPECAST_GENERIC \
Vector() noexcept : V({}) {} \
Vector(T x) noexcept { \
for (size_t i = 0; i < D; i++) V[i] = x; \
} \
template<typename T1, size_t D1> explicit operator Vector<T1, D1>() const noexcept { \
Vector<T1, D1> o; \
for (size_t i = 0; i < D1; ++i) \
o.V[i] = (i < D ? static_cast<T1>(V[i]) : 0); \
return o; \
} \
explicit operator const T* () const noexcept { return &V; } \
explicit operator T* () noexcept { return &V; } \
explicit operator bool() const noexcept { \
for (size_t i = 0; i < D; ++i) if(!V[i]) return false; \
return true; \
}
template<typename T, size_t D>
struct Vector {
T V[D];
STAMP_MATH_VECTOR_TYPECAST_GENERIC;
};
template <typename T>
struct Vector<T, 2> final {
constexpr static size_t D = 2;
union {
T V[2];
struct {
T x;
T y;
};
};
Vector(T x, T y) noexcept : x(x), y(y) {}
STAMP_MATH_VECTOR_TYPECAST_GENERIC;
};
Excerpt A - from project.
Alternate Solutions
In this section, I will dive into alternate solutions that came to mind after a few days of pondering.
Non-Member Conversion Operator Overload
This solution I feel will be the most supported, or generally the easiest to implement as almost all other operator overloads can be defined outside of the class (ex, implementing your own ?std::cout <<? function).
If we assume that Non-member conversion operator overloading can exist, we get:
template<typename T, size_t D>
struct Vector {
T V[D];
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
};
template <typename T>
struct Vector<T, 2> final {
constexpr static size_t D = 2;
union {
T V[2];
struct {
T x;
T y;
};
};
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
Vector(T x, T y) noexcept : x(x), y(y) {}
};
template<typename T, size_t D, typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i) o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
template<typename T, size_t D>
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
template<typename T, size_t D>
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
template<typename T, size_t D>
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
Excerpt B - for showcasing nonmember conversion overloading.
This implementation would behave the same as the code in Excerpt A.
Although this code is longer than my original example, I feel that this scales better and is easier to read. Let?s say we need Vector implementations all the way to Dimension 7, with members from X to W, A, B , C: not having to copy the same conversion operator will lead to cleaner code.
One potential rule that could be added is requiring the explicit keyword on all non-member conversion operators overloads, but this would add excessive limitation.
How would this affect existing code?
Yes, letting the user be able to create conversion operators willy-nilly could break projects that rely on a class not converting to different types, but I feel this could benefit way more than break. Furthermore, why would a user start adding typecasting randomly in a project? And couldn?t you do this by using member conversion operator overloading?
What would happen if this nonmember declaration already exists as a member operator overload?
I believe this should have similar implementation to other nonmember operator overloading and cause compilation errors.
Why hasn't this been implemented before?
Based on some research, I found only a Stack Overflow thread<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F34056443%2Fwhy-cant-i-overload-c-conversion-operators-outside-a-class-as-a-non-member-f&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218859586%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=eg9IL2t4NyGxbZLhXKAYRjIs%2FUs1LpAjRuAyphG9xU0%3D&reserved=0<https://stackoverflow.com/questions/34056443/why-cant-i-overload-c-conversion-operators-outside-a-class-as-a-non-member-f>> asking the same question 8 years ago with the answer being summarized as ?no one really cared about feature X enough to fight for it.? They also point out how this could create a lot of confusion for the compiler and reader, but I feel this operator overloading could greatly benefit projects such as the one I presented above.
Does This solve any other problems besides template specialization?
Conversion operator overloading could also solve other templated typecasting greatly simplifying codebases. I have not thought this through but I could come up with something if necessary.
Would this add excesses work for a compiler?
I don?t fully know how this will work, but this implementation should require the same number of conversion candidates as one would just have copy-pasted the conversion operators throughout all classes.
Why not create a separate function to act as a conversion operator?
Although, yes I could do this, the code would be less intuitive on first glance and lead to longer implementations of the vectors.
Vector<float, 2> A;
Vector<int, 4> B;
Auto C = A + ConvertVector<float, 2>(B);
Verse
Vector<float, 2> A;
Vector<int, 4> B;
Auto C = A (Vector<float, 2>)B;
Partial Template Specialization Act Similar to Class Inheritance
This solution would greatly alter existing implementations of partial specialization and so I feel this one will not be accepted, but I will still explore this option.
template<typename T, size_t D>
struct Vector {
T V[D];
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
template<typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i)
o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
};
template <typename T>
struct Vector<T, 2> final {
constexpr static size_t D = 2;
union {
T V[2];
struct {
T x;
T y;
};
};
Vector(T x, T y) noexcept : x(x), y(y) {}
};
Excerpt C ? for showcasing partial template specialization acting as class inheritance
In this example, I am suggesting that each member of the base templated class will be implicitly copied over to all implementations and if any duplicate members arise, the partial specialization member will take precedence. This implementation will act the same way as the above code.
So if you have ?Vector<float, 2> a {}; float* ptr = (float*)a;? the variable a will be defined with the partial specialization and will still have access to the base template members.
Would this break existing code?
Yes, fully. So, I would suggest having some keyword to explicitly tell the compiler that ?hey, this function should be copied to all partial specialization implementations.? Based on my understanding, the ISO committee does not like adding new keywords and so I feel this will be a dealbreaker.
How would members declared inside partial template specialization work?
The only members being copied over are from the original templated class and so no other confusion is present. This limitation I feel is necessary, as partial specialization already is very hard for the compiler to work with.
Why implement this in the C++ standard if it is no niche?
I agree, this suggestion is very specific to this problem, and I can?t imagine any other problems that require this solution.
Get/Set member
By using the getter/setter implementation, the Vector class can be one templated class without any partial specialization but then you would have a function ? such as w() ? that will be defined but will crash for vectors with dimensions 1, 2 or 3. Additionally this would require the parenthesis and would look less tidy. One workaround would be implementing a base Vector class and having child classes.
A solution to the parenthesis clutter could be an attribute which would allow the compiler to see a function name and implicitly call the getter, setter functions.
template<typename T, size_t D>
struct Vector {
T V[D];
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
template<typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i)
o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
};
template <typename T>
struct Vector2 final : Vector<T, 2> {
Vector(T x, T y) noexcept : {
this->x = x; //implicitly calls the setter.
this->y = y;
}
void [[setter]] x(T v) {
V[0] = v;
}
T [[getter]] x() {
return V[0];
}
void [[setter]] y(T v) {
V[1] = v;
}
T [[getter]] y() {
return V[1];
}
};
Excerpt D ? for showcasing getter setter attribute
I haven?t thought this one through, but I do feel C++ would benefit with this a lot more than the other solutions. Furthermore, this only partially solves my issue as I still need the partial template to use a matrix code (see ?Why implement the Vector as a partial template specialization?) and using a parent-child class would greatly increase the vector memory usage for any virtual functions (although possibly not a problem).
Union with ?Greedy/Nongreedy? Members
This is inspired from REGEX .+? , in which would take the least number of characters necessary for the match. By allowing a union to have ?optional? members which would only be accessible once the other members reach a certain size, you could implement the Vector class as:
template<typename T, size_t D>
struct Vector {
union {
T V[D];
struct [[nongreedy]] {
T x, y, z, w, a, b, c;
};
};
Vector() noexcept : V({}) {}
Vector(T x) noexcept {
for (size_t i = 0; i < D; i++) V[i] = x;
}
template<typename T1, size_t D1>
explicit operator Vector<T1, D1>(const Vector<T, D>& v) noexcept {
Vector<T1, D1> o;
for (size_t i = 0; i < D1; ++i)
o.V[i] = (i < D ? static_cast<T1>(v.V[i]) : 0);
return o;
}
explicit operator const T* (const Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator T* (Vector<T, D>& v) noexcept {
return &v.V;
}
explicit operator bool(const Vector<T, D>& v) noexcept {
for (size_t i = 0; i < D; ++i) if (!v.V[i]) return false;
return true;
}
};
Excerpt E ? for showcasing nongreedy union
This showcases a possible implementation of a nongreedy attribute in which would only give more members once ?T V[D];? reaches the size equivalent of the struct?s members. This solution is so niche and ?weird? when compared to other C++ features that I feel this solution will not be implemented.
Would this increase compiler complexity greatly?
Yes, that?s why I feel this solution is not the correct direction for the partial template problem.
Overload Dot Operator
This solution takes inspiration from LUA. I fully believe this goes against the spirit of C++ and so I won?t go further.
Potential Questions Unrelated to my suggestion
Why implement the Vector as a partial template specialization?
I have a compile time n*n matrix that uses the vector.
template<Quantity T, size_t Rows, size_t Cols> struct Matrix;
template<Quantity T, size_t Rows>
struct Matrix<T, Rows, 1> {
explicit Matrix(const Vector<T, Rows>& m) noexcept;
};
Excerpt Q1 - from project.
Furthermore, this solution could help other developers working with C++ and needing to go through the headache inducing problem solving.
Why use compile time declaration?
I need compile-time vector and matrix definitions for real time graphics rendering.
Why is this so in-depth for such a small problem?
I feel that having more options will greatly quicken the process of problem solving. Additionally I don?t want to spam this email with alternatives to this one problem.
Definitions of Terms
As I am not completely well versed in C++ terminology, I will add this section to showcase what I mean by some words. This is not meant to be patronizing but to help me better articulate my points.
Member ? Class scope declaration ? variables, functions, etc.
Non-member, nonmember ? namespace or global scope declarations.
Conversion, typecast ? converting between two types. ?static_cast<T2>(T1 value)?
Partial Specialization, partial template specialization ? https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fen.cppreference.com%2Fw%2Fcpp%2Flanguage%2Fpartial_specialization.html&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218868002%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=5zFzVArHDLt1m5gLEjDoVuK1mNr%2F2iDOm94CdzZ2flw%3D&reserved=0<https://en.cppreference.com/w/cpp/language/partial_specialization.html>
This file<https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdrive.google.com%2Ffile%2Fd%2F1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm%2Fview%3Fusp%3Dsharing&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218876158%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=n6%2BWjPTrc4WU8IfHkZpB08aEHuWnoEpAu2c%2B2fJyG%2Fc%3D&reserved=0<https://drive.google.com/file/d/1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm/view?usp=sharing>> <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdrive.google.com%2Ffile%2Fd%2F1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm%2Fview%3Fusp%3Dsharing&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218885536%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=Rj8cxrGRenrXy5iIWXy5feyTmrahFrw37Br8DEF3%2BF0%3D&reserved=0<https://drive.google.com/file/d/1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm/view?usp=sharing>> is the code that I have been referencing in "Current Solution".
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdrive.google.com%2Ffile%2Fd%2F1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm%2Fview%3Fusp%3Dsharing&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218897580%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=9Tn7vawPGM9X1xAfm9Ohmoxn9WBZs3jeUvprbh5TxBQ%3D&reserved=0<https://drive.google.com/file/d/1WdO0lAz2qvVbvIINaR5fqj61dt04mVGm/view?usp=sharing>
Please note that this email is mostly a draft and might contain errors.
-------------- next part --------------
HTML attachment scrubbed and removed
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: vector.h
URL: <https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.isocpp.org%2Fstd-proposals%2Fattachments%2F20250721%2F7baf2c05%2Fattachment.h&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218905953%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=EHk2njqrthG6qBme20U1EEezleV%2BLafGdKIIjYke0yA%3D&reserved=0<https://lists.isocpp.org/std-proposals/attachments/20250721/7baf2c05/attachment.h>>
------------------------------
Subject: Digest Footer
Std-Proposals mailing list
Std-Proposals_at_[hidden]
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flists.isocpp.org%2Fmailman%2Flistinfo.cgi%2Fstd-proposals&data=05%7C02%7C%7C37a2dfe0ae6d4163317808ddc884dfae%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638887195218914284%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=P8G2tk47VpJru6N2l3Nx0ISsE2mgojTBZJ90bRU8MQo%3D&reserved=0<https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals>
------------------------------
End of Std-Proposals Digest, Vol 76, Issue 59
*********************************************
Received on 2025-07-21 19:16:27