我有一个模板元函数,它扩展了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行 - 是&#34; typedef typename boost :: mpl :: transform&gt; :: type transformed;&#34;:
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'
答案 0 :(得分:1)
在以下行中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;
};