Closed ioshine closed 9 years ago
应该是 NO,这么严重的错误,竟然一直都没人发现。。。 :sweat:
感谢你指出,如果能直接发一个 Pull Request 来 fix 这个错误就更好了~ :yum:
另外,我考虑了一下,如果直接用 constexpr
来修饰 isShorter
肯定是不行。因为 std::string
根本无法被 constexpr
所修饰。但如果,稍微修改下 isShorter
呢?发现还是勉强可以的:
#include <iostream>
#include <string.h>
constexpr bool isShorter(const char* str1, const char* str2)
{
return strlen(str1) < strlen(str2);
}
int main()
{
std::cout << std::boolalpha << isShorter("hello", "pezy") << std::endl;
std::cout << std::boolalpha << isShorter("hello", "Xsimplify") << std::endl;
}
输出:
false
true
FYI
另外一种方式,最大程度的保留 isShorter
的形式:
#include <iostream>
#include <string>
class ConstString {
const char *s;
const int n;
public:
template<std::size_t N>
constexpr ConstString(const char(&a)[N]) : s(a), n(N-1) {}
constexpr char operator[](int i) { return ( i<0 || i>=n ? throw "error: out_of_range" : s[i]); }
constexpr int size() { return n; }
constexpr const char* c_str() { return s; }
operator std::string() const { return std::string(s, n); }
};
constexpr bool isShorter(const ConstString& str1, const ConstString& str2)
{
return str1.size() < str2.size();
}
int main()
{
ConstString str1("hello");
ConstString str2("Xsimplify");
std::cout << std::boolalpha << isShorter(str1, str2) << std::endl;
}
reference: constexpr specifier
谢谢解答,好效率~~ Pull Request 什么的还不会,渣渣的英语,我去学学。。。
看了回复的代码,诸多不懂,constexpr不能修饰std::string想都没想,其实string的概念都模模糊糊。。。 只水水的学了C语言,才开始学C++(c++primer才看到第六章),麻烦问下怎么学好C++?有没有写的好文章什么的,学学过来人的经验,非常感谢~~
@Xsimplify
个人认为,学 C++ 的方法很简单,但就难坚持。因为很复杂,也可能会很枯燥。
总的说,就上述三点。有 C 的基础很好,但要记住 C 和 C++ 是完全不同的两种语言,不要混着用。如果想更快的锻炼自己,可以多来这里回答回答问题。或是看书有不明白的地方,习题有迷惑的地方,在这里问。不出意外的话,12 小时之内,应该有人能帮你看看的。
:100: 加油~
@pezy 学习了,非常感谢~~
@Xsimplify
大部分同意@pezy 。就一点:CP5足够了,除非职业需要,否则不要看effective系列。
C++的学习意义很大程度上是对CS各个方向的延伸,诸如算法、操作系统、编译、CG、CV什么的。这些延伸比C++本身更重要、也更有意义。effective系列书籍,都是散点式不成体系的东西,仅仅是狭隘的就C++谈C++,一旦离开C++的工程语境,基本没多大用了。也就对C++项目有点儿意义,对个人成长来说纯属瞎耽误功夫。
差不多的精力,四个不同的分配方案: 1、effective系列仔细阅读; 2、算导前四章通读通刷; 3、学C#写个徒手量上千行的小项目; 4、学python,写个徒手量上500行的小项目;
方案1,顶多受益几个C++项目; 方案2,算法基础打牢了,受益终生; 方案3、4,绝对也是大开眼界的事儿,对C++的编程的助力也是超过方案1的。
我觉得虽然答案是no,但这个解释不对:
A constexpr function is defined like any other function but must meet certain restrictions: The return type and the type of each parameter in a must be a literal type. But
std::string
(parameter ofisShorter
) is not a literal type.
因为isShorter函数中形参是字面值(第59页说字面值包含算术符号、引用、指针,而改形参是一个string类型引用而不是string类型变量),下面是我的测试代码:
#include <iostream>
#include <string>
using namespace std;
constexpr bool isShorter(const string &s1, const string &s2) {
return &s1 == &s2;
}
int main (void) {
string s1 = "hello", s2 = "world";
isShorter(s1, s2);
return 0;
}
上面的代码能够测试通过,显然不是参数的问题。之后将上面代码中的return语句替换,得到下面代码:
#include <iostream>
#include <string>
using namespace std;
constexpr bool isShorter(const string &s1, const string &s2) {
return s1.size() == s2.size();
}
int main (void) {
string s1 = "hello", s2 = "world";
isShorter(s1, s2);
return 0;
}
编译就不通过了,而且错误点也出现在了size()这个地方,错误提示是“error, call to non-constexpr function”——size()是一个非constexpr函数。在下面的代码中我特意在constexpr函数中return一个non-constexpr函数:
inline bool Compare() { return true; }
constexpr bool isShorter(const string &s1, const string &s2) {
return Compare();
}
发现还是会提示”error, call to non-constexpr function“,说明constexpr函数中调用的函数也必须是constexpr函数。 因此错误点应该在size()不是一个constexpr函数,而不在于std::string身上。
@lookfiresu123 你是对的,谢谢 错误点应该在size()不是一个constexpr函数,而不在于std::string身上
为什么我这么写毫无警告就通过了编译?
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
constexpr bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
int main()
{
cout << isShorter("younger", "great") << endl;
return 0;
}
编译器问题,在clang++3.6下编译是能通过的,但在g++4.9下编译会出现call to con-constexpr
问题,也许你用的是clang++3.6。
分别对clang++3.6和g++4.9编译出来的可执行文件进行反汇编可得
g++4.9:
/home/lookfiresu/Desktop/test.cpp:8
s.size();
40076a: lea -0x20(%rbp),%rax
40076e: mov %rax,%rdi
400771: callq 400610 <_ZNKSs4sizeEv@plt>
clang++3.6:
/home/lookfiresu/Desktop/test.cpp:8
s.size();
4006ac: callq 400560 <_ZNKSs4sizeEv@plt>
4006b1: lea -0x10(%rbp),%rdi
编译阶段产生汇编代码,而上面的汇编代码中指出调用s.size()
调用callq
,这表示程序在栈中会进行相应的压栈操作,而这些都是在运行期完成的。所以string::size()
函数显然不会是一个constexpr
函数,又因为constexpr
函数中调用的函数(在return
语句中)也必须是constexpr
函数 —— prime5原话,因此isShorter()
函数不是constexpr
函数才对。
至于为什么clang++3.6没有报错,我也不清楚。
constexpr int test(const string &s) {
return 12;
}
int main() {
int a[test("test")];
return 0;
}
The code above produced a warning related to variable length arrays. Is this behavior related to the type conversion between const char *
and const string &
?
isShorter函数不能定义成constexpr函数吧?isShorter函数返回值要调用size函数,编译时不能确定结果吧,测试了下不行。。。 答案不该是YES 应该是NO吧?