如果在编译时知道边缘条件,我如何可以省去调用? [英] How can I elide a call if an edge condition is known at compile time?
问题描述
我有以下情况:有一个巨大的模板,如 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屋!