我有一个带有两个整数作为输入的模板。一个可能比另一个大。我的代码进行了相应的转换,因此结果适合目标类型。
以下是该功能的基本概念:
template<typename S, typename D>
D convert(S a)
{
return static_cast<D>(a);
}
但是,当S
和D
之间的大小改变时,我想移动该值。因此,我添加了一些条件:
if(sizeof(S) < sizeof(D))
{
return a << (sizeof(D) - sizeof(S)) * 8;
}
if(sizeof(S) > sizeof(D))
{
return a >> (sizeof(S) - sizeof(D)) * 8;
}
问题是我遇到了这些错误:
conversions.cpp:以'void convert(buffer_&)[具有S =无符号字符; D =短无符号int; buffer_t = std :: vector]’:
的宽度
conversions.cpp:从此处开始需要
conversions.cpp:错误:右移计数> =类型[-Werror = shift-count-overflow]d[idx] = convert_sign<S, D>(static_cast<std::int64_t>(s[idx]) >> (sizeof(S) - sizeof(D)) * 8);
_注意:对于那些不了解的人,在错误范围内的(sizeof(S) - sizeof(D))
或(sizeof(D) - sizeof(S))
在错误范围内。 >,因此它实际上与shift参数一样大(因为将shift参数视为无符号值,所以它非常大且不是负数,无论如何if()
返回一个无符号的sizeof()
。)>
很明显,我可以使用编译指示来忽略该警告并进行处理。
不过,我期望的是具有std::size_t
的{{1}}不会被编译,因此不会出现错误,因为这是在编译时发生的(即编译器知道{{ 1}}块将在编译时执行还是不执行。)是否有一种方法可以不使用该编译指示并仍然避免该错误?
答案 0 :(得分:4)
不过,我期望的是具有false的if()不会被编译,因此不会出现任何错误,因为这是在编译时发生的(即,编译器知道if()块是否将被执行或而不是在它编译的时候。)
您正在描述if constexpr
的行为,很不幸,该行为仅从C ++ 17开始可用
写作时
if constexpr ( some_compile_time_test )
some_code_1;
else
some_code_2;
其中some_compile_time_test
是可以决定编译时的测试(如sizeof(S) < sizeof(D)
),编译器编译some_code_1
-并完全忽略some_code_2
-测试为true
,反之亦然,否则
如果你只写
if ( some_test )
some_code_1;
else
some_code_2;
测试some_test
是否可推论编译时间并不重要:编译器可以优化代码,而忽略未使用的部分,但该部分必须是可编译的。
在C ++ 17之前的版本(主要但不仅限于C ++ 11和C ++ 14)中,您必须开发两个(或更多)不同的函数/方法。
查找“ SFINAE”和“标签分配”,以查看一些有用的方法。
SFINAE的示例
template <typename S, typename D>
typename std::enable_if<(sizeof(S)<sizeof(D)), S>::type convert (S a)
{ return a << (sizeof(D) - sizeof(S)) * 8; }
template <typename S, typename D>
typename std::enable_if<(sizeof(S)>sizeof(D)), S>::type convert (S a)
{ return a >> (sizeof(S) - sizeof(D)) * 8; }
和标签分发的示例(警告两者:未经测试的代码)
template <typename S, typename D>
S convert (S a, std::true_type)
{ return a << (sizeof(D) - sizeof(S)) * 8; }
template <typename S, typename D>
S convert (S a, std::false_type)
{ return a >> (sizeof(S) - sizeof(D)) * 8; }
template <typename S, typename D>
S convert (S a)
{ return convert<S, D>(a, std::integral_constant<bool, (sizeof(S)<sizeof(D))>{}); }