为什么is_integral认为std::string是整型?

3
这是一段针对C++17的短小程序:
#include <iostream>
#include <string>

using namespace std::string_literals;

int main() {
    std::string n = "asdf"s;

    if constexpr (std::is_integral<decltype(n)>::value) {
        std::cout << static_cast<int>(n) << std::endl;
    } else {
        std::cout << n << std::endl;
    }
    return 0;
}

但是它无法编译,因为显然 is_integral 认为 std::string 是整数型:

g++ -o main.o -c -std=c++17 -O2 -pipe -fPIC -fno-plt -fstack-protector-strong -Wall -Wshadow -pedantic -Wno-parentheses -Wfatal-errors main.cpp
main.cpp: In function 'int main()':
main.cpp:10:40: error: invalid static_cast from type 'std::__cxx11::string' {aka 'std::__cxx11::basic_string<char>'} to type 'int'
         std::cout << static_cast<int>(n) << std::endl;
                                        ^
compilation terminated due to -Wfatal-errors.

我该如何在编译时区分能够转换为int的内容和不能转换的内容?
这个问题与“为什么if constexpr使核心常量表达式错误消失不了?”不同,因为它不涉及模板(即使对于此情况,正确的用法可能是在模板上下文中)。即使主题相关,但这个问题本身也是不同的。
这个问题与“非模板类型的Constexpr if”不同,因为它具体涉及到std::is_integral的行为。

4
据我所知,if constexpr 的正确使用仅限于模板中,如果条件取决于模板参数。 - HolyBlackCat
将其放入模板中,它就会工作。http://coliru.stacked-crooked.com/a/24481706f6ebb93c - sp2danny
6
std::is_integral<std::string>::value 的值为 false。直接替换为 false 即可,问题不会改变。 - rustyx
1个回答

4

C++ 不允许您编写格式不正确的代码。让我们来看一个简单的例子:

int i = 0;
if constexpr (sizeof(int) > 98) { // never happen
    i = "a string";
}

在这里,编译器很容易看出constexpr的内容永远不会有效。就像static_assert(false)始终是致命错误一样。这是因为即使在constexpr if中未调用代码,其内容也会被ODR使用。

那么你问为什么模板是特例?为什么在模板中禁用无效代码是起作用的?事实上并没有特殊情况。将我的上面的代码放入模板中:

[](auto) { // this is a template
    int i = 0;
    if constexpr (sizeof(int) > 98) { // never happen
        i = "a string"; // same error
    }
}

这是因为编译器仍然可以证明此代码对于任何模板实例化都是无效的。
但是,如果您在constexpr if中使用依赖指令,那么编译器将非常难以"证明"没有任何模板实例化使其有效。看看这个修改后的示例:
[](auto a) { // this is a template
    if constexpr (sizeof(a) > 98) { // maybe happen
        a = "a string"; // no error?
    }
}

编译器无法证明 a 的类型不会超过98,并且无法证明您永远不会将字符串字面量分配给它。在代码中的任何位置添加一个新类型,可能满足此表达式。这类似于使用模板类的成员函数时的行为:如果该函数在给定模板参数的情况下不会导致有效实例化,则只要不使用该函数,就可以了。


该赋值是针对字符串字面量的,也就是一个数组 const char[somenumber]。是的,它通常会衰减为指针,但这并不意味着它是指针,也不是必然的。 - Deduplicator

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接