如何拥有“constexpr和运行时”别名

时间:2014-01-03 10:55:44

标签: c++ optimization c++11 compiler-optimization

Constexpr非常适合编译优化。例如......

strlen(char*)

可以使用....预编译。

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

在优化时,它给运行成本“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.

是否存在可以使用单个统一功能的现有宏/模板黑客攻击。即

constexpr size_t strlen_smart(char* baseChar) {
    #if constexpr
    ... constexpr function
    #else its runtime
    ... runtime function
}

或者某些超载黑客会允许以下

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

inline size_t strlen_smart(char* baseChar) {
    ... runtime function
}

注意:此问题适用于一般概念。有两个单独的函数用于运行时和constexpr而不是给定的示例函数。

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

1 个答案:

答案 0 :(得分:10)

我不知道任何通用的方法,但我知道有两种可能的特定情况。

某些编译器的具体情况

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

#define strlen_smart(s) \
    (__builtin_constant_p(s) && __builtin_constant_p(*s) ? \
        strlen_constexpr(s) : \
        strlen(s))

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

奖励:文字的特定情况(不是实际答案)

对于strlen的特定强制转换,您可以使用以下事实:字符串文字类型为const char *,但类型为const char[N],隐式转换为{ {1}}。但它也会转换为const char *,而const char (&)[N]则不会。

所以你可以定义:

const char *

(明显template <size_t N> constexpr size_t strlen_smart(const char (&array)[N]) strlen_smart转发const char *}

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

strlen

这有问题

template <size_t N>
size_t strlen_smart(const char (&)[N]) { return N - 1; }

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