ReadingLab / Discussion-for-Cpp

C++ 中文讨论区
MIT License
88 stars 63 forks source link

6.46的答案不对吧? #22

Closed ioshine closed 9 years ago

ioshine commented 9 years ago

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

pezy commented 9 years ago

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

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

pezy commented 9 years ago

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

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

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

ioshine commented 9 years ago

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

pezy commented 9 years ago

@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 小时之内,应该有人能帮你看看的。

:100: 加油~

ioshine commented 9 years ago

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

Mooophy commented 9 years ago

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

lookfiresu123 commented 8 years ago

我觉得虽然答案是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 commented 8 years ago

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

ShenTensen commented 8 years ago

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

#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 commented 8 years ago

编译器问题,在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 commented 7 years ago
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 &?