根据编译时常量参数运行不同的函数

问题描述 投票:0回答:1

我有这个函数可以用 N 字节的重复模式填充缓冲区。

void* memsetPattern(void* buf, size_t bufSize, const void* Pattern, size_t PatternSize) {
    if (buf == nullptr || Pattern == nullptr || PatternSize == 0) { return nullptr; }
    if (bufSize == 0) { return buf; } // 0 Bytes to copy
    if (PatternSize == 1) {
        memset(buf, ((uint8_t*)Pattern)[0], bufSize);
        return buf;
    }
    /* otherwise, if PatternSize >= 2 */
}

如果 PatternSize 是 1 个字节,该函数将改为运行

memset(buf, ((uint8_t*)Pattern)[0], bufSize)
,因为 memset 的运行速度比我的函数稍快。

如果用户想调用

memsetPattern(buf, bufSize, Pattern, 1)
,是否可以直接调用
(Pattern != nullptr && buf != nullptr) ? memset(buf, ((uint8_t*)Pattern)[0], bufSize) : nullptr
,因为在编译时PatternSize等于1字节?

我想一种方法是使用宏,但感觉不对。

#define memsetPattern_Macro(buf, bufSize, Pattern, PatternSize) \
(PatternSize == 1) ? ( \
    (Pattern != nullptr && buf != nullptr) ? memset(buf, ((uint8_t*)Pattern)[0], bufSize) : nullptr \
) : memsetPattern(buf, bufSize, Pattern, PatternSize)

环顾四周,我确实找到了

if constexpr ()
,但是当我尝试
if constexpr (PatternSize == 1) {
时,它给出了错误,因为
'PatternSize' is not a constant expression

我应该如何根据编译时已知的参数来切换函数?我需要更改传递给 memsetPattern() 函数的参数类型吗?

c++ constexpr if-constexpr
1个回答
0
投票

如果用户想要调用

memsetPattern(buf, bufSize, Pattern, 1)
,是否可以直接调用
(Pattern != nullptr && buf != nullptr) ? memset(buf, ((uint8_t*)Pattern)[0], bufSize) : nullptr
,因为在编译时已知
PatternSize
等于1个字节?

是的,这正是您已经在做的事情。 任何优化编译器都已经内联函数,然后利用已知常量,例如

Pattern
始终为
1

例如,如果您编写以下内容:

void* foo(void* buf, size_t bufSize, const void* Pattern) {
    return memsetPattern(buf, bufSize, Pattern, 1);
}

...然后 GCC 将其优化为(https://godbolt.org/z/W16E6ffee):

foo(void*, unsigned long, void const*):
        test    rdi, rdi
        je      .L17
        test    rdx, rdx
        je      .L17
        test    rsi, rsi
        je      .L22
        sub     rsp, 8
        movzx   eax, BYTE PTR [rdx]
        mov     rdx, rsi
        mov     esi, eax
        call    memset
        ...

无条件调用

memset
之前的唯一分支是测试
buf
Pattern
bufSize
是否为零/空。
PatternSize == 1
PatternSize == 0
的测试已完全删除。

您之前可能已经被告知:不要过早优化。对你的编译器有信心。

© www.soinside.com 2019 - 2024. All rights reserved.