Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6.46的答案不对吧? #22

Closed
ioshine opened this issue May 13, 2015 · 13 comments
Closed

6.46的答案不对吧? #22

ioshine opened this issue May 13, 2015 · 13 comments
Labels

Comments

@ioshine
Copy link

ioshine commented May 13, 2015

isShorter函数不能定义成constexpr函数吧?isShorter函数返回值要调用size函数,编译时不能确定结果吧,测试了下不行。。。
答案不该是YES 应该是NO吧?

@pezy pezy added the bug label May 13, 2015
@pezy
Copy link
Member

pezy commented May 13, 2015

应该是 NO,这么严重的错误,竟然一直都没人发现。。。 😓

感谢你指出,如果能直接发一个 Pull Request 来 fix 这个错误就更好了~ 😋

@pezy
Copy link
Member

pezy commented May 13, 2015

另外,我考虑了一下,如果直接用 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

@pezy
Copy link
Member

pezy commented May 13, 2015

另外一种方式,最大程度的保留 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

@ioshine
Copy link
Author

ioshine commented May 13, 2015

谢谢解答,好效率~~
Pull Request 什么的还不会,渣渣的英语,我去学学。。。

@ioshine
Copy link
Author

ioshine commented May 13, 2015

看了回复的代码,诸多不懂,constexpr不能修饰std::string想都没想,其实string的概念都模模糊糊。。。
只水水的学了C语言,才开始学C++(c++primer才看到第六章),麻烦问下怎么学好C++?有没有写的好文章什么的,学学过来人的经验,非常感谢~~

@pezy
Copy link
Member

pezy commented May 13, 2015

@Xsimplify

个人认为,学 C++ 的方法很简单,但就难坚持。因为很复杂,也可能会很枯燥。

  1. 就读这本《C++ Primer 5th》,一定要做全部习题。更细致的读书方法请参考我在知乎上的一个答案:
    http://www.zhihu.com/question/26536792/answer/33175086
  2. 读 Effective 三部曲,链接请见 http://segmentfault.com/q/1010000002593186/a-1020000002593197
  3. 上述四本书读完,那么基础就算扎实了,具体表现为不会再纠结一些小白问题了。下面的道路就需要通过实践来磨练了。一些练手的方法请见:http://www.zhihu.com/question/29112393/answer/43461605

总的说,就上述三点。有 C 的基础很好,但要记住 C 和 C++ 是完全不同的两种语言,不要混着用。如果想更快的锻炼自己,可以多来这里回答回答问题。或是看书有不明白的地方,习题有迷惑的地方,在这里问。不出意外的话,12 小时之内,应该有人能帮你看看的。

💯 加油~

@ioshine
Copy link
Author

ioshine commented May 14, 2015

@pezy
学习了,非常感谢~~

@Mooophy
Copy link
Contributor

Mooophy commented May 14, 2015

@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的。

pezy added a commit to pezy/CppPrimer that referenced this issue May 26, 2015
@lookfiresu123
Copy link

我觉得虽然答案是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 of isShorter) 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身上。

@zuchuanzhang
Copy link

@lookfiresu123 你是对的,谢谢
错误点应该在size()不是一个constexpr函数,而不在于std::string身上

pezy added a commit to Mooophy/Cpp-Primer that referenced this issue Apr 11, 2016
@ShenTensen
Copy link

为什么我这么写毫无警告就通过了编译?

#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;
}

@lookfiresu123
Copy link

编译器问题,在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没有报错,我也不清楚。

@jsvoid
Copy link

jsvoid commented Nov 4, 2016

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 &?

0iui0 pushed a commit to 0iui0/Cpp-Primer that referenced this issue Jun 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants