Date: Tue, 1 Oct 2019 13:56:26 -0400
[I apologize for my mistakes, I wrote the email very quickly]
2 things here:
1. "constexpr" would ideally need to be treated like a qualifier. This
way it could propagate like cv qualifier.
template<class U>
struct construct {
template<class QT, class T = std::remove_cvref_t<QT&&>, class =
std::enable_if_t<std::is_same_v<T, U>>>
QT&& operator()(node_proxy&, QT&& po) {
return T(po);
}
};
struct node_proxy {};
node_proxy __x;
struct ConstClass
{
constexpr ConstClass() {}
};
struct NonConstClass
{
NonConstClass() {}
};
// This will result in:
construct<ConstClass>()(__x, ConstClass()); // constexpr expression
construct<NonConstClass>()(__x, NonConstClass()); // not a constexpr
expression
2. The "qualifier" template token would be:
- the only way to qualify the "this" parameter;
- syntactic sugar:
template<class T>
struct construct {
template<qualifier Q1, qualifier Q2>
Q1 T&& operator()(node_proxy&, Q1 T&& po) Q2 {
return T(po);
}
};
// This will result in:
construct<ConstClass> c1()
c1(__x, ConstClass()); // constexpr expression
construct<NonConstClass> volatile const c2()
c2(__x, NonConstClass()); // not a constexpr expression from an
arbitrary "volatile const" object
2 things here:
1. "constexpr" would ideally need to be treated like a qualifier. This
way it could propagate like cv qualifier.
template<class U>
struct construct {
template<class QT, class T = std::remove_cvref_t<QT&&>, class =
std::enable_if_t<std::is_same_v<T, U>>>
QT&& operator()(node_proxy&, QT&& po) {
return T(po);
}
};
struct node_proxy {};
node_proxy __x;
struct ConstClass
{
constexpr ConstClass() {}
};
struct NonConstClass
{
NonConstClass() {}
};
// This will result in:
construct<ConstClass>()(__x, ConstClass()); // constexpr expression
construct<NonConstClass>()(__x, NonConstClass()); // not a constexpr
expression
2. The "qualifier" template token would be:
- the only way to qualify the "this" parameter;
- syntactic sugar:
template<class T>
struct construct {
template<qualifier Q1, qualifier Q2>
Q1 T&& operator()(node_proxy&, Q1 T&& po) Q2 {
return T(po);
}
};
// This will result in:
construct<ConstClass> c1()
c1(__x, ConstClass()); // constexpr expression
construct<NonConstClass> volatile const c2()
c2(__x, NonConstClass()); // not a constexpr expression from an
arbitrary "volatile const" object
-- *Phil Bouchard* Founder C.: (819) 328-4743 Fornux Logo <http://www.fornux.com> On 9/30/19 9:51 AM, Arthur O'Dwyer wrote: > On Sun, Sep 29, 2019 at 4:51 PM Phil Bouchard via Std-Proposals > <std-proposals_at_[hidden] > <mailto:std-proposals_at_[hidden]>> wrote: > > > > [Please CC my personal email address in the replies otherwise I'll > can't properly follow-up] > > > > So let's take a better example: > > > > template <typename T> > > struct construct<T> { > > // Let the compiler generate the most efficient code > > template <qualifier Q> > > inline T Q operator()(node_proxy & __y, T Q po) { > > return T(po); > > } > > }; > > > > struct ConstClass { > > constexpr ConstClass() {} > > }; > > > > struct NonConstClass { > > NonConstClass() {} > > }; > > > > // This will result in: > > construct<ConstClass>()(ConstClass()); // constexpr expression > > construct<NonConstClass>()(NonConstClass()); // not a constexpr > expression > > Well, I see two or three factual errors here, plus one or two > fundamental errors. > 1. `construct<ConstClass>()(ConstClass())` will not compile as > written, because `operator()` takes two parameters, not one. You > didn't provide any argument corresponding to parameter `__y`. > 2. `construct<ConstClass>()(ConstClass())` will not be a compile-time > constant, because you didn't mark `operator()` as constexpr. > (Remember, the `constexpr` keyword on a function already means > "conditionally constexpr"! You don't need any special tricks to > achieve conditional constexpr-ness.) > 3. You wrote `template<typename T> construct<T>` as if it were a > partial specialization, but I'm going to assume that was a typo. > 4. An rvalue of type `T` is not convertible to a return type of `T &`, > nor to `volatile T &&`. Do you think this is a problem for your code? > 5 (fundamental). You still seem to be assuming that `Q` can deduce as > "none." Please, consider the ramifications of permitting a template > that can deduce either `foo(const int& i)` or `foo(int i)`. Please > understand that that overload set would be irretrievably ambiguous and > your template would never be usable. > 6 (fundamental). Do you know about */dangling references?/* What do > you think happens to your return type when Q is a reference type? > > So, with the understanding that again your own code fails to achieve > what you say it does, I would think that the closest C++17 to this > would be > > template<class U> > struct construct { > template<class QT, class T = std::remove_cvref_t > <https://en.cppreference.com/w/cpp/types/remove_cvref><QT&&>, class = > std::enable_if_t<std::is_same_v<T, U>>> > constexpr QT&& operator()(node_proxy&, QT&& po) { > return T(po); > } > }; > > Notice that this is valid C++03 too, if you polyfill > <https://en.wikipedia.org/wiki/Polyfill_(programming)> the library > type-traits — e.g. if you use `typename std::enable_if<B>::type` in > place of `std::enable_if_t<B>`. > > > > > Thus qualifiers would be: > [...] > > const volatile constexpr > > `constexpr` is not a qualifier. > > –Arthur
Received on 2019-10-01 12:58:38