如何拥有"constexpr和运行时"别名

Pic*_*tor 22 c++ optimization compiler-optimization c++11

Constexpr对编译优化非常有用.例如...

strlen(char*)
Run Code Online (Sandbox Code Playgroud)

可以使用....预编译

constexpr inline size_t strlen_constexpr(char* baseChar) {
    return (
            ( baseChar[0] == 0 )
            ?(// if {
              0
              )// }
            :(// else {
              strlen_constexpr( baseChar+1 ) + 1 
              )// }
            );
}
Run Code Online (Sandbox Code Playgroud)

这在优化时给它的运行时成本为"0"但是在运行时速度超过10 + x

// Test results ran on a 2010 macbook air
--------- strlen ---------
Time took for 100,000 runs:1054us.
Avg Time took for 1 run: 0.01054us.
--------- strlen_constexpr ---------
Time took for 100,000 runs:19098us.
Avg Time took for 1 run: 0.19098us.
Run Code Online (Sandbox Code Playgroud)

是否有任何现有的宏/模板黑客可以使用单个统一功能.即.

constexpr size_t strlen_smart(char* baseChar) {
    #if constexpr
    ... constexpr function
    #else its runtime
    ... runtime function
}
Run Code Online (Sandbox Code Playgroud)

或者一些超载黑客可以允许以下内容

constexpr size_t strlen_smart(char* baseChar) {
    ... constexpr function
}

inline size_t strlen_smart(char* baseChar) {
    ... runtime function
}
Run Code Online (Sandbox Code Playgroud)

注意:这个问题一般适用于概念.为运行时和constexpr提供2个单独的函数,而不是给出的示例函数.

免责声明:将编译器设置为-O3(优化级别)足以修复99.9%的静态字符串优化,使上面的所有示例"毫无意义".但这不是这个问题的重点,因为它适用于其他"例子",而不仅仅是strlen.

Jan*_*dec 11

我不知道任何通用的方法,但我知道两种具体的情况.

一些编译器的具体情况

另外gcc和clang复制了gcc的所有功能,它具有内置功能__builtin_constant_p.我不确定gcc是否会正确地将内联函数的参数视为常量,但我担心你必须从宏中使用它:

#define strlen_smart(s) \
    (__builtin_constant_p(s) && __builtin_constant_p(*s) ? \
        strlen_constexpr(s) : \
        strlen(s))
Run Code Online (Sandbox Code Playgroud)

可能有用.请注意,我正在测试constexpr s*sconstexpr,因为指向静态缓冲区的指针一个编译时常量,而它的长度则不是.

额外奖励:文字的具体情况(不是实际答案)

对于特定的强制转换,strlen您可以使用以下事实:字符串文字不是类型,const char *而是const char[N]隐式转换为的类型const char *.但它也转换const char (&)[N]为同时const char *没有.

所以你可以定义:

template <size_t N>
constexpr size_t strlen_smart(const char (&array)[N])
Run Code Online (Sandbox Code Playgroud)

(显然strlen_smartconst char *前锋上strlen)

我有时使用这种类型的参数的函数,即使在C++ 98中定义对应(我没有尝试重载strlen自身,但重载是这样我可以避免调用它):

template <size_t N>
size_t strlen_smart(const char (&)[N]) { return N - 1; }
Run Code Online (Sandbox Code Playgroud)

这有问题

char buffer[10] = { 0 };

strlen_smart(buffer);
Run Code Online (Sandbox Code Playgroud)

应该说0,但是那个优化的变体只是说9.这些函数在这样的缓冲区上调用没有意义,所以我不在乎.