用stoi声明的Const Int不被认为是const

时间:2018-05-08 05:55:30

标签: c++

我使用CGAL编写了一个简单的测试程序,并遇到了以下问题:

点在上面定义为

typedef K::Point_d Point;

但我不认为这是相关的。

当我尝试按如下方式编译程序时:

const int size = 10;
Point P[size];

g ++没有问题。

如果我试图编译:

const int size = stoi("10");
Point P[size]

我收到以下错误

error: variable length array of non-POD element type 'Point' (aka 'Point_d<Cartesian_d<double,
  CGAL::Linear_algebraCd<double, std::__1::allocator<double> > > >')

为什么从字符串中检索时,size被视为变量而不是const?

6 个答案:

答案 0 :(得分:2)

C ++将特定事物定义为已定义的常量表达式,以便在编译时知道 - 请参阅constant_expression

通常,未定义为constexpr的函数不会通过它们。你可以尝试强制它:

#include<string>

constexpr int x = std::stoi("10");
int main() {
    return 0;
}

但你会发现这仍然会导致错误:

error: call to non-constexpr function 'int std::stoi(const string&, std::size_t*, int)'

所以,你运气不好,因为stoi不是一个常数表达式。如果你真的坚持,你可以使用你自己的实现覆盖它,例如How do I convert a C string to a int at compile time?

答案 1 :(得分:1)

在编译时不评估

stoi 。这意味着编译器不知道数组应该有多大。 如果你想做类似的事情,你必须使用constexpr函数(constexpr function)。这些可以在编译时进行评估,然后就可以了。

答案 2 :(得分:1)

编译器不理解stoi函数的语义。所有它看到的是你调用一个返回一个整数的函数(该函数是否可以内联并优化掉是一个单独的语义问题)。

对于编译器,

之间的语义差异很小
const int size = stoi("10");

const int size = getchar();

正如其他答案提到的那样constexpr是例外。我只是想我说明这个问题。

答案 3 :(得分:1)

第一个const int size = 10;是编译时const表达式,它可以在编译期间计算, 但const int size = stoi("10")不是编译时const表达式,因此无法编译。 std::stoi不是在编译时评估的constexpr函数。

如果您想拥有此功能,可能需要创建一个constexpr函数来评估编译时间。

constexpr bool is_digit(char c) {
    return c <= '9' && c >= '0';
}

constexpr int stoi_impl(const char* str, int value = 0) {
    return *str ?
            is_digit(*str) ?
                stoi_impl(str + 1, (*str - '0') + value * 10)
                : throw "compile-time-error: not a digit"
            : value;
}

constexpr int to_int(const char* str) {
    return stoi_impl(str);
}


int main() {
    constexpr int size = to_int("10");
    int arr[size];
}

这将编译; [从here复制]

答案 4 :(得分:1)

在第一个代码示例中

const int size = 10;
Point P[size];

size的特定值可以在编译时使用 ,因为它已知(您已指定)。因此,编译器可以用特定值替换它的所有用途,而不用实际创建变量。

在第二个样本中

const int size = stoi("10");
Point P[size]

编译器无法知道该值,因为它是由stoi函数在运行时推导出来的。因此,它无法替换数组的大小(必须事先知道它以确定现在要分配的内存),并且您会收到错误。

在C ++ 11中有 constexpr 惯用法,它允许在编译时评估一些声明为constexpr的函数。但是在你的情况下stoi不是constexpr函数,所以你无法使用这个特定的函数实现你想要的。你可以实现自己的constexpr stoi,但我没有看到很多,因为在这种情况下你的代码会包含这样的东西:my_constexpr_stoi("10"),即参数总是手动编写并始终事先知道。为什么不写10

答案 5 :(得分:0)

为了扩展kabanus的答案,语言标准说在C ++ 11中绑定的数组必须是一个称为整数常量表达式的数组。 C ++ 17略微放松了这一点并允许更多的东西,但现在这并不重要。

This page at cppreference列出了 允许在常量表达式中执行的所有操作。它基本上引用了语言标准。

允许您的第一个示例的相关部分是8a。除非将const变量初始化为常量表达式,否则不允许使用变量。因此,使用初始化为常量表达式const整数类型变量的名称是合法的,如第一个示例中所示。数值常量是常量表达式,因此size是一个const变量,初始化为常量表达式,即A-OK。

但是,由于第2点,如果函数调用都声明为constexpr并且已经定义,则它们只是常量表达式。因此,对于可在代码中的数组表达式中使用的标准库函数,需要将其声明为constexpr并在头文件中定义。

该标准没有说明stoi()符合条件,但我认为其中没有任何内容直接禁止某些实施提供此作为扩展。