简体   繁体   中英

Why can't a template reference type be used as a template typealias argument?

I'm currently writing an iterator for a custom collection-style class. I had a mutable iterator class that worked perfectly, but decided it would be best to also implement a const version that would block modifications of the object whose contents are being iterated. I decided to avoid a separate class and code repetition by using a suggestion I found online to use conditional typing.

I defined the iterator_traits typealiases in the typical C++11 fashion that would allow code-sharing and template argument-dependent const or mutable behavior (ItemType is a template parameter on the outer container class):

template<bool Const = false>
class iterator {
public:
    using reference = std::conditional_t<Const, const ItemType &, ItemType &>;
    using pointer = std::conditional_t<Const, const ItemType *, ItemType *>;

    //Rest of the iterator_traits and some other typealiases

    ...

    template<bool _Const = Const>
    std::enable_if_t<_Const, value_type>
    operator*() const
    {
        //Return copy
    }
     //Non-const version
    template<bool _Const = Const>
    std::enable_if_t<!_Const, reference>
    operator*()
    {
        //Return modifiable reference type
    }
    ...
}

I decided to try to remove the repetitive std::conditional_t calls by creating another template typealias like this:

template<typename type>
using const_conditional = std::conditional_t<Const, const type, type>;

and replacing all the std::conditional_t<...> with const_conditional<some_type_here> . This seems to work universally for the outer class template parameter ItemType type, but not for the outer class type itself when its type is a reference, as in const_conditional<MyCollection<ItemType> &> . Upon compiling, the compiler complains that I am discarding qualifiers, meaning the const isn't being applied, so I'm therefore breaking const requirements, yet replacing my custom typealias with the original std::conditional_t code compiles and works just as expected, and I have no clue why.

I can of course simply go back to using the std::conditional_t calls I was using originally, which worked fine, but they seemed bloated and repetitive, and I don't understand why my custom typealias fails. Searches across the internet failed to help me in my specific situation. Any help would be very sincerely appreciated.

ItemType& and ItemType* are types themselves, and so adding a const qualifier yields ItemType& const (in which case const is silently ignored as a result of template argument substitution) and ItemType* const , respectively, which is different than expected const ItemType& and const ItemType* . For the latter, you could use:

template <typename type>
using const_conditional = std::conditional_t<Const, const type, type>;
// ...

using reference = const_conditional<ItemType>&;
using pointer = const_conditional<ItemType>*;

DEMO


As a side note, _Const is a reserved identifier, as all other that start with an underscore followed by an uppercase letter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM