代码之家  ›  专栏  ›  技术社区  ›  SoronelHaetir

C++模板代码适用于msvc 2015,但不适用于2017

  •  0
  • SoronelHaetir  · 技术社区  · 8 年前

    我有一个模板元函数,它扩展了std::make\u-signed以处理元组类型,即将std::make\u-signed应用于元组的每个组件类型。它使用boost::mpl完成大部分工作。

    在使用vc2015进行编译时,它可以正常工作,但在切换到2017年时则无法正常工作(我使用vs2017,并在项目设置中翻转了平台工具集配置,没有其他更改,并见证了这种行为)。错误隐藏在boost mpl中,我不确定这是我的代码中的错误,是boost::mpl中的错误还是msvc2017中的错误。

    我非常感谢您帮助我追踪这里发生的事情。

    下面的示例是我完整的测试项目,甚至可以禁用PCH。

    #include <cstdint>
    #include <tuple>
    #include <type_traits>
    
    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/transform.hpp>
    #include <boost/mpl/equal_to.hpp>
    #include <boost/mpl/distance.hpp>
    #include <boost/mpl/int.hpp>
    #include <boost/mpl/deref.hpp>
    #include <boost/mpl/reverse.hpp>
    
    //
    // hcc_meta::to_variadic is a metafunction that takes a boost::mpl sequence and produces a variadic template argument pack.
    // It is based on code from http://bx12.blogspot.com/2010/04/converting-mpl-sequence-to-variadic.html
    // One improvement that has been made is that the template type to pass the expanded argument pack to is now taken as a template template parameter rather than being hard-coded.
    namespace hcc_meta
    {
        namespace impl
        {
            template<typename F, typename L>
            struct exit_ : boost::mpl::equal_to<typename boost::mpl::distance<F, L>::type, typename boost::mpl::int_<0>>
            {
            };
    
            template<typename F, typename L, bool exit, template <typename ...> class TargType, typename ... Args>
            struct to_variadic
            {
                typedef typename boost::mpl::deref<F>::type front_;
                typedef typename boost::mpl::next<F>::type next_;
                typedef typename impl::exit_<next_, L>::type exit_;
                typedef typename to_variadic<next_, L, exit_::value, TargType, front_, Args...>::type type;
            };
    
            template<typename F, typename L, template<typename ...> class TargType, typename ... Args>
            struct to_variadic<F, L, true, TargType, Args...>
            {
                typedef TargType<Args...> type;
            };
    
            template<typename Seq>
            struct seq_traits
            {
                typedef typename boost::mpl::begin<Seq>::type first_;
                typedef typename boost::mpl::end<Seq>::type last_;
                typedef typename impl::exit_<first_, last_>::type exit_;
            };
        }//impl
    
        template<typename Seq, template <typename ...> class TargType>
        struct to_variadic
        {
            typedef typename boost::mpl::reverse<Seq>::type reversed_;
            typedef typename impl::to_variadic<typename impl::seq_traits<reversed_>::first_, typename impl::seq_traits<reversed_>::last_, impl::seq_traits<Seq>::exit_::value, TargType>::type type;
        };
    }
    
        // Defines a static member 'value' that is 'true' if 'Ty' is a specialization of std;::tuple.
        template<typename Ty>
        struct is_std_tuple
        {
            static bool const value = false;
        };
        template<typename ... Types>
        struct is_std_tuple<std::tuple<Types...>>
        {
            static bool const value = true;
        };
    
        //
            // Helper that only applies std::make_signed to types that can take it.
            // For all other types 'type' is an alias for 'Ty'.
        template<typename Ty>
        struct make_signed_if_possible
        {
    #pragma warning(push)
    #pragma warning(disable : 4348) // 'make_signed_if_possible<U1>::apply': redefinition of default parameter: parameter 2 
            // Use a nested template to hide the use of the default template argument from users of make_signed_if_possible.
            template<typename Ty, bool = std::is_integral<Ty>::value || std::is_enum<Ty>::value || is_std_tuple<Ty>::value>
            struct apply;
    #pragma warning(pop)
            template<typename Ty>
            struct apply<Ty, true>
            {
                typedef typename std::make_signed<Ty>::type type;
            };
            template<typename Ty>
            struct apply<Ty, false>
            {
                typedef Ty type;
            };
            typedef typename apply<Ty>::type type;
        };
    
        // Define the std::make_signed metafunction for tuples.
        // The type member is a tuple with the same number of members as the input but with each element that makes a signedness distinction transformed to the signed variant.
        template<typename ... Types>
        struct std::make_signed<std::tuple<Types...>>
        {
            typedef boost::mpl::vector<Types...> seq;
            typedef typename boost::mpl::transform<seq, typename make_signed_if_possible<boost::mpl::_1>>::type transformed;
            typedef typename hcc_meta::to_variadic<transformed, std::tuple>::type type;
        };
    
        int main()
        {
            typedef std::tuple<std::uint64_t, std::uint64_t> utypes;
            using stypes = typename std::make_signed<utypes>::type;
            return 0;
        }
    

    使用vc2017构建时,我遇到以下错误。作为参考,我自己的代码的第一行是testbed的第101行。cpp-是“typedef typename boost::mpl::transform>::type transformed;”:

    1>d:\devtools\boost_1_66_0\boost\mpl\clear.hpp(30): error C2903: 'apply': symbol is neither a class template nor a function template
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see reference to class template instantiation 'boost::mpl::clear<P1>' being compiled
    1>        with
    1>        [
    1>            P1=make_signed_if_possible<boost::mpl::_1>
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\eval_if.hpp(41): note: see reference to class template instantiation 'boost::mpl::transform1<Seq1,Seq2OrOperation,OperationOrInserter>' being compiled
    1>        with
    1>        [
    1>            Seq1=make_signed_if_possible<boost::mpl::_1>,
    1>            Seq2OrOperation=boost::mpl::na,
    1>            OperationOrInserter=boost::mpl::na
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(138): note: see reference to class template instantiation 'boost::mpl::eval_if<boost::mpl::or_<boost::mpl::is_na<boost::mpl::na>,boost::mpl::is_lambda_expression<Seq2OrOperation>,boost::mpl::not_<boost::mpl::is_sequence<boost::mpl::na>>,boost::mpl::false_,boost::mpl::false_>,boost::mpl::transform1<Seq1,Seq2OrOperation,OperationOrInserter>,boost::mpl::transform2<Seq1,Seq2OrOperation,OperationOrInserter,Inserter>>' being compiled
    1>        with
    1>        [
    1>            Seq2OrOperation=boost::mpl::na,
    1>            Seq1=make_signed_if_possible<boost::mpl::_1>,
    1>            OperationOrInserter=boost::mpl::na,
    1>            Inserter=boost::mpl::na
    1>        ]
    1>z:\projects\testbed\testbed\testbed.cpp(101): note: see reference to class template instantiation 'boost::mpl::transform<make_signed_if_possible<boost::mpl::_1>,boost::mpl::na,boost::mpl::na,boost::mpl::na>' being compiled
    1>z:\projects\testbed\testbed\testbed.cpp(108): note: see reference to class template instantiation 'std::make_signed<utypes>' being compiled
    1>d:\devtools\boost_1_66_0\boost\mpl\clear.hpp(30): error C3770: 'unknown-type': is not a valid base class
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2039: 'type': is not a member of 'boost::mpl::clear<P1>'
    1>        with
    1>        [
    1>            P1=make_signed_if_possible<boost::mpl::_1>
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see declaration of 'boost::mpl::clear<P1>'
    1>        with
    1>        [
    1>            P1=make_signed_if_possible<boost::mpl::_1>
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2146: syntax error: missing '>' before identifier 'type'
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2146: syntax error: missing '>' before identifier 'type'
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): error C2146: syntax error: missing '>' before identifier 'type'
    1>d:\devtools\boost_1_66_0\boost\mpl\push_back.hpp(42): error C2903: 'apply': symbol is neither a class template nor a function template
    1>d:\devtools\boost_1_66_0\boost\mpl\if.hpp(63): note: see reference to class template instantiation 'boost::mpl::has_push_back<int>' being compiled
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see reference to class template instantiation 'boost::mpl::if_<boost::mpl::has_push_back<int>,boost::mpl::aux::transform1_impl<P1,P2,boost::mpl::back_inserter<int>>,boost::mpl::aux::reverse_transform1_impl<P1,P2,boost::mpl::front_inserter<int>>>' being compiled
    1>        with
    1>        [
    1>            P1=make_signed_if_possible<boost::mpl::_1>,
    1>            P2=boost::mpl::na
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\push_back.hpp(42): error C3770: 'unknown-type': is not a valid base class
    1>d:\devtools\boost_1_66_0\boost\mpl\if.hpp(63): error C2039: 'value': is not a member of 'boost::mpl::has_push_back<int>'
    1>d:\devtools\boost_1_66_0\boost\mpl\transform.hpp(113): note: see declaration of 'boost::mpl::has_push_back<int>'
    1>d:\devtools\boost_1_66_0\boost\mpl\if.hpp(63): error C2065: 'value': undeclared identifier
    1>d:\devtools\boost_1_66_0\boost\mpl\if.hpp(67): error C2975: 'C': invalid template argument for 'boost::mpl::if_c', expected compile-time constant expression
    1>d:\devtools\boost_1_66_0\boost\mpl\if.hpp(30): note: see declaration of 'C'
    1>d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): error C2039: 'type': is not a member of 'boost::mpl::clear<P1>'
    1>        with
    1>        [
    1>            P1=int
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): note: see declaration of 'boost::mpl::clear<P1>'
    1>        with
    1>        [
    1>            P1=int
    1>        ]
    1>d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): error C2146: syntax error: missing '>' before identifier 'type'
    1>d:\devtools\boost_1_66_0\boost\mpl\copy.hpp(54): error C2146: syntax error: missing '>' before identifier 'type'
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   user7860670    8 年前

    删除不必要的 typename 之前 make_signed_if_possible 在以下行上应使其工作:

    typedef typename boost::mpl::transform<seq, make_signed_if_possible<boost::mpl::_1>>::type transformed;
    

    这个警告似乎是错误的,但可以通过定义 apply 外面:

    template<typename Ty, bool = std::is_integral<Ty>::value || std::is_enum<Ty>::value || is_std_tuple<Ty>::value>
    struct make_signed_if_possible_impl;
    
    template<typename Ty>
    struct make_signed_if_possible_impl<Ty, true>
    {
        typedef typename std::make_signed<Ty>::type type;
    };
    
    template<typename Ty>
    struct make_signed_if_possible_impl<Ty, false>
    {
        typedef Ty type;
    };
    
    //
    // Helper that only applies std::make_signed to types that can take it.
    // For all other types 'type' is an alias for 'Ty'.
    template<typename Ty>
    struct make_signed_if_possible
    {
        typedef typename make_signed_if_possible_impl<Ty>::type type;
    };