【问题标题】:Is it possible to avoid errors in parts of a c++ template function that are not going to run in the end?是否可以避免最终不会运行的 c++ 模板函数的部分错误?
【发布时间】:2019-05-07 19:38:18
【问题描述】:

我有一个带有两个整数作为输入的模板。一个可能比另一个有更大的类型。我的代码进行了相应的转换,因此结果适合 目标类型

下面是函数的基本思路:

template<typename S, typename D>
D convert(S a)
{
     return static_cast<D>(a);
}

但是,当SD 之间的大小发生变化时,我想改变这个值。所以我添加了几个条件:

    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_&) [with S = unsigned char; D = 短无符号整数; 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))错误 if() 块中将是否定,因此被视为真的大作为移位参数(由于移位参数被视为无符号值,因此它非常大并且不是负数,无论如何sizeof() 返回一个无符号的std::size_t。)

显然,我可以使用编译指示忽略警告并完成它。

不过,我所期待的是,具有 falseif() 不会被编译,因此不会出现错误,因为这发生在编译时(即编译器知道 if() 块是否会在编译时执行或不执行。)有没有办法不使用编译指示并仍然避免错误?

【问题讨论】:

  • 你试过if constexpr吗?
  • @max66,做到了!它在 C++17 下编译,带有constexpr。伟大的!随意写一个关于它的答案。

标签: c++ templates c++14 c++17 template-meta-programming


【解决方案1】:

不过,我所期望的是,具有 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) &lt; 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))>{}); }

【讨论】:

  • 对,我确信它得到了适当的优化。但是为了避免错误,它甚至不需要编译......这发生在优化之前。对于 C++14 及更早版本,我将得到诊断 #pragma
  • @AlexisWilke - 通过几个 SFINAE 和标签调度示例改进了答案;希望这会有所帮助。
  • 太好了,我最终使用了std::enable_if&lt;&gt;,因为我添加了对float 的支持,并且破坏了很多东西......使用SFINAE,它全部编译,我只有现在写几个测试来验证它是正确的。
猜你喜欢
  • 1970-01-01
  • 2013-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
相关资源
最近更新 更多