如果在编译时知道边缘条件,我如何可以省去调用? [英] How can I elide a call if an edge condition is known at compile time?

查看:126
本文介绍了如果在编译时知道边缘条件,我如何可以省去调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下情况:有一个巨大的模板,如 std :: vector 将调用 memmove()移动数组的部分。有时他们想要移动零长度零 - 例如,如果数组尾被删除(如 std :: vector :: erase()),他们将想要移动数组的其余部分,这将发生在长度为零,并且零将在编译时被知道(我看到反汇编 - 编译器知道),但编译器仍然会发出 memmove()调用。

I have the following situation: there's a huge set of templates like std::vector that will call memmove() to move parts of array. Sometimes they will want to "move" parts of length zero - for example, if the array tail is removed (like std::vector::erase()), they will want to move the remainder of the array which will happen to have length zero and that zero will be known at compile time (I saw the disassembly - the compiler is aware) yet the compiler will still emit a memmove() call.

所以基本上我可以有一个包装:

So basically I could have a wrapper:

inline void callMemmove( void* dest, const void* source, size_t count )
{
   if( count > 0 ) {
       memmove( dest, source, count );
   }
}

但这会引入额外的运行时检查 count 在编译时不知道,我不想要。

but this would introduce an extra runtime check in cases count is not known in compile time that I don't want.

是不是有可能使用 __假设提示,以指示编译器如果它确定 count 是零,它应该消除 memmove()

Is it somehow possible to use __assume hint to indicate to the compiler that if it knows for sure that count is zero it should eliminate the memmove()?

推荐答案

此解决方案使用 C ++编译时常数检测 - 诀窍使用事实编译时整数零可以转换为指针,这可以与过载一起使用检查编译时知道属性。

This solution uses a trick described in C++ compile-time constant detection - the trick uses the fact compile time integer zero can be converted to a pointer, and this can be used together with overloading to check for the "compile time known" property.

struct chkconst {
  struct Small {char a;};
  struct Big: Small {char b;};
  struct Temp { Temp( int x ) {} };
  static Small chk2( void* ) { return Small(); }
  static Big chk2( Temp  ) { return Big(); }
};

#define is_const_0(X) (sizeof(chkconst::chk2(X))<sizeof(chkconst::Big))
#define is_const(X) is_const_0( int(X)-int(X) )

#define memmove_smart(dst,src,n) do { \
    if (is_const(n)) {if (n>0) memmove(dst,src,n);} \
    else memmove(dst,src,n); \
  } while (false)

只检查零,无论如何,可以直接使用is_const_0为最大的简单性和可移植性:

Or, in your case, as you want to check for zero only anyway, one could use is_const_0 directly for maximum simplicity and portability:

#define memmove_smart(dst,src,n) if (is_const_0(n)) {} else memmove(dst,src,n)

这里的代码使用的is_const的一个版本比链接的问题更简单。这是因为Visual Studio在这种情况下比GCC更符合标准。如果定位gcc,您可以使用以下is_const variant(适用于处理所有可能的整数值,包括negative和INT_MAX):

Note: the code here used a version of is_const simpler than in the linked question. This is because Visual Studio is more standard conformant than GCC in this case. If targeting gcc, you could use following is_const variant (adapted to handle all possible integral values, including negative and INT_MAX):

#define is_const_0(X) (sizeof(chkconst::chk2(X))<sizeof(chkconst::Big))
#define is_const_pos(X) is_const_0( int(X)^(int(X)&INT_MAX) )
#define is_const(X) (is_const_pos(X)|is_const_pos(-int(X))|is_const_pos(-(int(X)+1)))

这篇关于如果在编译时知道边缘条件,我如何可以省去调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆