lundi 8 août 2022

error C2955: 'std::decay': use of class template requires template argument list

I wrote a template class RWHelper, and wanted to use it to write iterators. But it failed to compiled in VS2019 toolset=v140, which is c++11. On the other hand, it's passed in c++14, which means VS2019 toolset=v142. The compilation error is as follows: error C2955: std::decay: use of class template requires template argument list, and I don't know why the expression defer\<It\> in std::decay\<defer\<It\>\>::type is not deduced.

#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <cstdint>

#include <vector>
#include <string>

namespace detail
{
    template <typename T>
    using void_t = void;

    template <template <class...> class Test, class, class... Args>
    struct is_detected : std::false_type {};

    template <template <class...> class Test, class... Args>
    struct is_detected<Test, void_t<Test<Args...>>, Args...> : std::true_type {};

    template <typename T>
    using is_explicitly_dereferenceable_test = decltype(std::declval<T>().operator*());

    template <template <class> class Test, class, class Args>
    struct defer { typedef typename std::remove_pointer<typename std::decay<Args>::type>::type type; };

    template <template <class> class Test, class Args>
    struct defer<Test, void_t<Test<Args>>, Args> { typedef Test<Args> type; };
}

template <template <class...> class Trait, class... Args>
using is_detected = typename detail::is_detected<Trait, void, Args...>::type;

template <typename T>
using is_pointer_like = std::integral_constant<bool,
    !std::is_array<T>::value &&
    (std::is_pointer<T>::value || is_detected<detail::is_explicitly_dereferenceable_test, T>::value)
>;

template<typename T>
using defer= typename detail::defer<detail::is_explicitly_dereferenceable_test, void, T>::type;

namespace utility
{
    class RWHelper
    {
    public:
        template <typename It>
        void Write(It first, It last)
        {
            Write<It, typename std::decay<defer<It>>::type>(first, last, 
                std::integral_constant < bool,
                    is_pointer_like<It>::value &
                    std::is_same<
                        typename std::decay<decltype(*std::declval<It>())>::type,
                        std::string
                    >::value
                >()
            );
        }

        template <typename It, typename Item>
        void Write(It first, It last, std::false_type) 
        {
            std::cout << "[1]: {It = " << typeid(It).name() << ", Item = " << typeid(Item).name() << "}" << std::endl;
        }

        template <typename It, typename Item>
        void Write(It first, It last, std::true_type) {
            std::cout << "[2]: {It = " << typeid(It).name() << ", Item = " << typeid(Item).name() << "}" << std::endl;
        }
    };
}


int main()
{
    utility::RWHelper h;

    // the following commented code can't be compiled in c++11 and report an error (see the title)
    // but it's well in C++14. I don't know why
    /*{
        char s[] = { "adsf" };
        h.Write( s + 0, s + 5);
        std::cout << std::endl;
    }*/

    {

        std::string s{ "sdfasdf" };
        h.Write( s.begin(), s.end());
        std::cout << std::endl;
    }

    return 0;
}

Aucun commentaire:

Enregistrer un commentaire