首页 文章

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

提问于
浏览
0

我有一个模板元函数,它扩展了std :: make_signed,以便能够处理元组类型,即将std :: make_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.cpp的第101行 - 是“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 回答

  • 1

    在以下行中删除 make_signed_if_possible 之前不必要的 typename 应该可以使它工作:

    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;
    };
    

相关问题