I was about to suggest the following [intermediate & incomplete] code:

#include <iostream>

using namespace std;


template <typename T>
    struct StackIteratorBase
    {
        T * next;
    };

template <typename T, bool Const = false, bool Volatile = false>
    struct StackIterator : StackIteratorBase<T>
    {
        using StackIteratorBase<T>::next;

        T * get() { return next; }
    };

template <typename T>
    struct StackIterator<T, true, false> : StackIteratorBase<T>
    {
        using StackIteratorBase<T>::next;

        T const * get() const { return next; }
    };

template <typename T>
    struct StackIterator<T, false, true> : StackIteratorBase<T>
    {
        using StackIteratorBase<T>::next;

        T volatile * get() volatile { return next; }
    };

template <typename T>
    struct StackIterator<T, true, true> : StackIteratorBase<T>
    {
        using StackIteratorBase<T>::next;

        T const volatile * get() const volatile { return next; }
    };

int main()
{
    StackIterator<int> i;

    cout << i.get() << endl;

    return 0;
}

But Brian came up with a better syntax.

Personally I'm not sure about P0847 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0847r2.html#name-lookup-candidate-functions), because it seems to apply to "this" only whereas my goal is to stay generic, extensible and use a pretty syntax as much as possible.


--

Phil Bouchard
Founder
C.: (819) 328-4743

Fornux Logo


On 10/4/19 1:15 AM, Phil Bouchard wrote:

2. a) Like I was saying before, the need for the "const" overloads on the "this" parameter forces us to create redundant code and disregards the "volatile" qualifier:

https://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a06712.html


2. b) The only solution I can foresee is to add a new "qualifier" template token type:

template <qualifier Q>

    iterator     end () Q noexcept;
 
template <qualifier Q>

    Q T &     front () Q noexcept;


2. c) It is also a much cleaner syntax for other use cases:

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>>>
                constexpr QT&& operator()(node_proxy&, QT&& po)

                {
                    return T(po);
                }
    };

We can use instead this much cleaner alternative:

template<class T>
    struct construct

    {
        template<qualifier Q>
                constexpr Q T&& operator()(node_proxy&, Q T&& po)

                {
                    return T(po);
                }
    };

And if "constexpr" becomes a qualifier then simply:

template<class T>
    struct construct

    {
        template<qualifier Q>
                Q T&& operator()(node_proxy&, Q T&& po)

                {
                    return T(po);
                }
    };


Thanks,

--

Phil Bouchard
Founder
C.: (819) 328-4743

Fornux Logo


On 10/3/19 4:07 PM, Arthur O'Dwyer wrote:
On Thu, Oct 3, 2019 at 12:26 AM Phil Bouchard <phil@fornux.com> wrote:

Verdict?


Phil, you should pause and try to come up with a motivating example for the feature you claim to want.
Once you have a motivating example, the next step would be to look at what would be the best way to solve it. Maybe there's even a better way than what you originally proposed as a feature!
That is, start with a problem, and then propose a solution for the problem. If (by thinking) you end up realizing that you don't have a problem after all, that's actually a good thing.

You do need to slow down and think about your examples. Here's your latest one:

    template <typename T>
    struct construct
    {
        T operator () (node_proxy &, T && t) { return T(t); } // will lose constexpr
    };

And here's the perfectly valid C++11 code that solves your stated problem:

    template <typename T>
    struct construct
    {
        constexpr T operator () (node_proxy &, T && t) { return T(t); } // no longer loses constexpr
    };
 
See also: http://sscce.org

–Arthur