__PRETTY_FUNCTION__以常量表达式

时间:2019-04-25 13:06:47

标签: c++ c++17 constant-expression

请参考以下代码段:

#include <type_traits>
#include <string_view>

constexpr std::size_t strlen(char const* s) {
    std::size_t n = 0;
    while (*s++ != '\0')
        ++n;
    return n;
}

template <std::size_t>
struct X {};

int main() {
    constexpr auto pf = __PRETTY_FUNCTION__; // gcc ok; clang ok; (1)
    static_assert(std::string_view(__PRETTY_FUNCTION__) == std::string_view("int main()")); // gcc ok; clang ok; (2)
    X<strlen(__PRETTY_FUNCTION__)> x; // gcc not ok; clang ok; (3)
}

Clang 8可以编译它,但是GCC 8.3不能。参见godbolt。尽管行(3)(1)没问题,但GCC在行(2)上失败了。 如果我能够在pf行中声明(1)并在__PRETTY_FUNCTION__中使用static_assert,则意味着表达式__PRETTY_FUNCTION__是核心常量表达式。而且如果我无法声明X<strlen(__PRETTY_FUNCTION__)> x,则意味着strlen(__PRETTY_FUNCTION__)不是整数常量表达式。

那么为什么strlen(__PRETTY_FUNCTION__)不是整数常量表达式?是标准隐含的,还是GCC错误?

2 个答案:

答案 0 :(得分:5)

numeric不是标准的。这样,编译器可以在不同的地方(在解析,构建AST或链接时)实现它。

如果应该在解析时实现,则它可以是一个常量表达式(我想这就是clang所做的事情)。 但是,如果它是在链接时实现的(也就是说,编译器会为其发出符号,而链接器将对其进行解析),则它不能是常量表达式。

我认为海湾合作委员会使用后一种情况。

请注意,在这种情况下,您可以使用它们的sizeof(),因为如果需要编译时常量字符串的长度计算,它是Bitmap Bolden(Bitmap bmp0) { float f = 2f; Bitmap bmp = new Bitmap(bmp0.Width, bmp0.Height); using (Bitmap bmp1 = new Bitmap(bmp0, new Size((int)( bmp0.Width * f), (int)( bmp0.Height * f)))) { float contrast = 1f; ColorMatrix colorMatrix = new ColorMatrix(new float[][] { new float[] {contrast, 0, 0, 0, 0}, new float[] {0,contrast, 0, 0, 0}, new float[] {0, 0, contrast, 0, 0}, new float[] {0, 0, 0, 1, 0}, new float[] {0, 0, 0, 0, 1} }); ImageAttributes attributes = new ImageAttributes(); attributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); attributes.SetGamma(7.5f, ColorAdjustType.Bitmap); using (Graphics g = Graphics.FromImage(bmp)) g.DrawImage(bmp1, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp1.Width, bmp1.Height, GraphicsUnit.Pixel, attributes); } return bmp; } 。 因此,将表达式3替换为:

__PRETTY_FUNCTION__

,它将在两个编译器上都可以正常编译。

编辑:正如NathanOliver指出的那样,GCC似乎将const char[]的签名视为X<sizeof(__PRETTY_FUNCTION__) - 1> x; ,而clang / visual studio则将其视为__PRETTY_FUNCTION__。这在GCC中是一个令人讨厌的麻烦(不是错误,因为它不是标准的),并且他们似乎已在> 8.0.0版本中对其进行了修复。

在表达式(1)和表达式(2)中,static const char[]衰减为static constexpr const char[](指针是常数,但是关于数据什么也不能说)。对我来说,表达式(2)不能证明任何事情,因为不能保证指针在相等的两面都应该相等,即使它们指向“相同”的内容也是如此。 __PRETTY_FUNCTION__构造函数期望const char*,因此,除string_view之外的任何可能衰减到const char*的东西都将传递表达式(2)。

答案 1 :(得分:0)

我仍然担心(2)行,因此我发现注释中不适合的内容。

我对代码段做了一些修改,请参阅this

#include <type_traits>
#include <string_view>

constexpr std::size_t strlen(char const* s) {
    std::size_t n = 0;
    while (*s++ != '\0')
        ++n;
    return n;
}

template <std::size_t>
struct X {};

static char const PF[] = "int main()";

int main() {
    constexpr auto pf = std::string_view(__PRETTY_FUNCTION__); // gcc ok; clang ok; (1)
    static_assert(pf == std::string_view("int main()")); // gcc ok; clang ok; (2)
    X<strlen(__PRETTY_FUNCTION__)> x; // gcc not ok; clang ok; (3)

    static_assert(pf[0] == 'i'); // not ok; (4)
    X<pf.size()> x1; // ok; (5)
    X<strlen(pf.data())> x2; // not ok; (6)

    static_assert(__builtin_constant_p(pf.data()) == 0); // ok (7)
    static_assert(__builtin_strlen(pf.data()) == 10); // ok (8)
    static_assert(__builtin_memcmp(pf.data(), "int main()", __builtin_strlen(pf.data())) == 0); // ok (9)
    static_assert(std::char_traits<char>::compare(pf.data(), "int main()", std::char_traits<char>::length(pf.data())) == 0); // ok (10)

    static_assert(std::char_traits<char>::length(PF) == 10); // not ok (11)
    static_assert(__builtin_strlen(PF) == 10); // not ok (12)
}

据我了解,如果static_assert不是(2)表达式是constexpr(如第believe行),(4)将无法证明(2)的值。但是,尽管(4)(5)行有问题,但std::char_traits<char>行对于GCC似乎还可以。因此,我偷看了__builtin_constant_p。这些特征使用__builtin_*strlen实现和我的(7)之类的实现之间分配。第__PRETTY_FUNCTION__行指出“无法证明__builtin_memcmp(__PRETTY_FUNCTION__)的恒定性”(请参阅​​gcc doc),尽管表达式(8)可以在编译时求值(请参阅第(11)行)。

(12)__PRETTY_FUNCTION__中考虑失败,可以得出结论,在某些情况下,static constexpr char const []的行为就好像它被宣布为static char const [],而在其他情况下,则是{ {1}}。换句话说,如果__PRETTY_FUNCTION__具有类型,则在编译的所有步骤中它都是不一致的(我参考GCC 8.3)。