Visual C++ 模板代码适用于 MSVC 2015,但不适用于 2017
visual C++ template code works in msvc 2015 but not 2017
我有一个模板元函数,它扩展了 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 构建时出现以下错误。作为参考,我自己的代码的第一行 - 测试平台的第 101 行.cpp - 是"typedef typename boost::mpl::transform>::type transformed;":
1>d:devtoolsboost_1_66_0boostmplclear.hpp(30): error C2903: 'apply': symbol is neither a class template nor a function template
1>d:devtoolsboost_1_66_0boostmpltransform.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:devtoolsboost_1_66_0boostmpleval_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:devtoolsboost_1_66_0boostmpltransform.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:projectstestbedtestbedtestbed.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:projectstestbedtestbedtestbed.cpp(108): note: see reference to class template instantiation 'std::make_signed<utypes>' being compiled
1>d:devtoolsboost_1_66_0boostmplclear.hpp(30): error C3770: 'unknown-type': is not a valid base class
1>d:devtoolsboost_1_66_0boostmpltransform.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:devtoolsboost_1_66_0boostmpltransform.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:devtoolsboost_1_66_0boostmpltransform.hpp(113): error C2146: syntax error: missing '>' before identifier 'type'
1>d:devtoolsboost_1_66_0boostmpltransform.hpp(113): error C2146: syntax error: missing '>' before identifier 'type'
1>d:devtoolsboost_1_66_0boostmpltransform.hpp(113): error C2146: syntax error: missing '>' before identifier 'type'
1>d:devtoolsboost_1_66_0boostmplpush_back.hpp(42): error C2903: 'apply': symbol is neither a class template nor a function template
1>d:devtoolsboost_1_66_0boostmplif.hpp(63): note: see reference to class template instantiation 'boost::mpl::has_push_back<int>' being compiled
1>d:devtoolsboost_1_66_0boostmpltransform.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:devtoolsboost_1_66_0boostmplpush_back.hpp(42): error C3770: 'unknown-type': is not a valid base class
1>d:devtoolsboost_1_66_0boostmplif.hpp(63): error C2039: 'value': is not a member of 'boost::mpl::has_push_back<int>'
1>d:devtoolsboost_1_66_0boostmpltransform.hpp(113): note: see declaration of 'boost::mpl::has_push_back<int>'
1>d:devtoolsboost_1_66_0boostmplif.hpp(63): error C2065: 'value': undeclared identifier
1>d:devtoolsboost_1_66_0boostmplif.hpp(67): error C2975: 'C': invalid template argument for 'boost::mpl::if_c', expected compile-time constant expression
1>d:devtoolsboost_1_66_0boostmplif.hpp(30): note: see declaration of 'C'
1>d:devtoolsboost_1_66_0boostmplcopy.hpp(54): error C2039: 'type': is not a member of 'boost::mpl::clear<P1>'
1> with
1> [
1> P1=int
1> ]
1>d:devtoolsboost_1_66_0boostmplcopy.hpp(54): note: see declaration of 'boost::mpl::clear<P1>'
1> with
1> [
1> P1=int
1> ]
1>d:devtoolsboost_1_66_0boostmplcopy.hpp(54): error C2146: syntax error: missing '>' before identifier 'type'
1>d:devtoolsboost_1_66_0boostmplcopy.hpp(54): error C2146: syntax error: missing '>' before identifier 'type'
在以下行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;
};
相关文章:
- OpenGL - 在 NDC 中计算位置适用于着色器,但不适用于'regular'程序
- 使用模板参数重载C++方法:如何使其适用于模板的子类?
- 如何修复我的最大公约数代码?它适用于除零和零以外的所有数字
- 选择排序C++(已修改)并非适用于所有情况
- 无法让"std::enable_if"适用于无作用域枚举
- 请找出我的代码中的错误,它在提交得到错误答案的同时仍然适用于我的所有测试用例
- 确定夏令时是否适用于特定日期
- 是否有一种 STL 算法可以最后找到,但它也适用于指针?
- 十进制到二进制的实现不能完全适用于我大学的检查器。问题或提示可能是什么
- 使用程序集嵌入数据时"Undefined reference"错误,使用适用于窗口的 mingw-w64 编译(COFF 而不是 ELF)
- 为什么 std::vector 适用于类定义中的不完整类型?
- 为什么哈希<常量字符*>适用于字符串而不是字符串变量?
- Lambda适用于最新的Visual Studio,但在其他地方不起作用
- 我该如何文档文档以使文档适用于类成员而不是匿名类型
- 计算 c# 中二进制文件符号的频率不起作用,但适用于等效的 c++ 代码
- 为什么 fstream.open(文件名) 适用于文字而不是生成的字符串?
- 模板重载和 SFINAE 仅适用于函数而不是类
- 为什么链接器不抱怨多个函数定义(仅适用于模板化函数)
- 我可以使用' == '来比较两个向量吗?我试过了,似乎工作正常。但我不知道它是否适用于更复杂的情况
- 延长临时的生命周期,适用于块范围的聚合,但不是通过"新";为什么?