Why can const char* const & = “hello†compile?
Clash Royale CLAN TAG#URR8PPP
up vote
41
down vote
favorite
I am reading a code snippet from a book and find this:
const char* const & a = "hello"; //can compile
const char*& a = "hello"; //cannot
All I know is that when initializing a reference, the array to pointer conversion would not take place.
const char* const &
, a reference to a const pointer
, the pointer points to const char
.
const char*&
, a reference to a pointer
, the pointer points to const char
.
So why does adding an extra const
, indicating that the pointer is a const
, allow it to compile?
c++ reference const language-lawyer
add a comment |Â
up vote
41
down vote
favorite
I am reading a code snippet from a book and find this:
const char* const & a = "hello"; //can compile
const char*& a = "hello"; //cannot
All I know is that when initializing a reference, the array to pointer conversion would not take place.
const char* const &
, a reference to a const pointer
, the pointer points to const char
.
const char*&
, a reference to a pointer
, the pointer points to const char
.
So why does adding an extra const
, indicating that the pointer is a const
, allow it to compile?
c++ reference const language-lawyer
add a comment |Â
up vote
41
down vote
favorite
up vote
41
down vote
favorite
I am reading a code snippet from a book and find this:
const char* const & a = "hello"; //can compile
const char*& a = "hello"; //cannot
All I know is that when initializing a reference, the array to pointer conversion would not take place.
const char* const &
, a reference to a const pointer
, the pointer points to const char
.
const char*&
, a reference to a pointer
, the pointer points to const char
.
So why does adding an extra const
, indicating that the pointer is a const
, allow it to compile?
c++ reference const language-lawyer
I am reading a code snippet from a book and find this:
const char* const & a = "hello"; //can compile
const char*& a = "hello"; //cannot
All I know is that when initializing a reference, the array to pointer conversion would not take place.
const char* const &
, a reference to a const pointer
, the pointer points to const char
.
const char*&
, a reference to a pointer
, the pointer points to const char
.
So why does adding an extra const
, indicating that the pointer is a const
, allow it to compile?
c++ reference const language-lawyer
edited Aug 27 at 15:23


Boann
35.6k1184116
35.6k1184116
asked Aug 27 at 4:39


Rick
1,309724
1,309724
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
34
down vote
accepted
It's essentially adhering to this formula
T const & a = something_convertible_to_T;
Where T is const char*
. In the first case, a temporary pointer can be materialized, assigned the address of the literal, and then have itself bound to the reference. In the second case, since the lvalue reference isn't const, it can't happen. Another example of more of the same
const char* && a = "hello"; // rvalue ref makes a no into a yes.
Now the temporary pointer is bound to an rvalue reference.
5
Yes I get it know. It's the same reason as forconst int& a = 3; //yes
,int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.
– Rick
Aug 27 at 5:03
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.
– StoryTeller
Aug 27 at 7:34
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
1
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
 |Â
show 8 more comments
up vote
6
down vote
Some additional phrasing for the bored, after reading the superb answer by StoryTeller, as I had to go through a different thought process about this.
So syntactically, In both lines we define a reference a
, and in both we shall have a materialization of a temporary pointer that takes the address of the string literal. The only difference between the two is the 2nd const
appearing only here:
const char* const & a = "hello";
and not here:
const char*& a = "hello";
This 2nd const
denotes that the object being referenced here, a pointer in this case, is itself const, as in it cannot be modified using this reference.
Hence, because the type of this string literal is const char[6]
(and not const char *
for example), our lvalue
reference to type const char*
in the second line cannot bind to it -- but the reference in the first line, being a reference to type const char* const
could. Why? Because of the rules of reference initialization:
[A reference to type “cv1 T1†is initialized by an expression of type “cv2 T2†as follows: ...]
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2
As in, our T in this quoted text is const char*
, and only in the first line it is cv-qualified no less than our object
. i.e. const char[6]
has the semantics of a const pointer, as opposed to just pointer to const.
The Clang error for the second line, read with that in mind, tells us exactly this:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
The part about being non-const lvalue reference is exactly that -- the lvalue in our case is a pointer to const
, but itself isn't const! Unlike the first line.
For this exact reason, this can compiles error-free:
char* const & a = "hello";
ISO C++11 warning aside, a compiler lets this one pass (not that it should, as the string literal is a 'const char [6]' and we shouldn't be dropping this first const
), as the reference is now const
with regards to its object, the pointer.
Another interesting thing is that An rvalue
reference const char* && a
(no "2nd const
") could bind to the temporary pointer that has materialized from the string literal, as StoryTeller provided himself. Why is that? Because of the rules of array to pointer conversion:
An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to a prvalue of type "pointer to T".
No mention of const
or other cv-qualification phrasing in here, but this stands only as long as we're initializing an rvalue ref.
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
34
down vote
accepted
It's essentially adhering to this formula
T const & a = something_convertible_to_T;
Where T is const char*
. In the first case, a temporary pointer can be materialized, assigned the address of the literal, and then have itself bound to the reference. In the second case, since the lvalue reference isn't const, it can't happen. Another example of more of the same
const char* && a = "hello"; // rvalue ref makes a no into a yes.
Now the temporary pointer is bound to an rvalue reference.
5
Yes I get it know. It's the same reason as forconst int& a = 3; //yes
,int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.
– Rick
Aug 27 at 5:03
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.
– StoryTeller
Aug 27 at 7:34
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
1
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
 |Â
show 8 more comments
up vote
34
down vote
accepted
It's essentially adhering to this formula
T const & a = something_convertible_to_T;
Where T is const char*
. In the first case, a temporary pointer can be materialized, assigned the address of the literal, and then have itself bound to the reference. In the second case, since the lvalue reference isn't const, it can't happen. Another example of more of the same
const char* && a = "hello"; // rvalue ref makes a no into a yes.
Now the temporary pointer is bound to an rvalue reference.
5
Yes I get it know. It's the same reason as forconst int& a = 3; //yes
,int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.
– Rick
Aug 27 at 5:03
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.
– StoryTeller
Aug 27 at 7:34
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
1
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
 |Â
show 8 more comments
up vote
34
down vote
accepted
up vote
34
down vote
accepted
It's essentially adhering to this formula
T const & a = something_convertible_to_T;
Where T is const char*
. In the first case, a temporary pointer can be materialized, assigned the address of the literal, and then have itself bound to the reference. In the second case, since the lvalue reference isn't const, it can't happen. Another example of more of the same
const char* && a = "hello"; // rvalue ref makes a no into a yes.
Now the temporary pointer is bound to an rvalue reference.
It's essentially adhering to this formula
T const & a = something_convertible_to_T;
Where T is const char*
. In the first case, a temporary pointer can be materialized, assigned the address of the literal, and then have itself bound to the reference. In the second case, since the lvalue reference isn't const, it can't happen. Another example of more of the same
const char* && a = "hello"; // rvalue ref makes a no into a yes.
Now the temporary pointer is bound to an rvalue reference.
edited Aug 27 at 5:03
answered Aug 27 at 4:42
StoryTeller
82.4k12163228
82.4k12163228
5
Yes I get it know. It's the same reason as forconst int& a = 3; //yes
,int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.
– Rick
Aug 27 at 5:03
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.
– StoryTeller
Aug 27 at 7:34
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
1
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
 |Â
show 8 more comments
5
Yes I get it know. It's the same reason as forconst int& a = 3; //yes
,int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.
– Rick
Aug 27 at 5:03
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.
– StoryTeller
Aug 27 at 7:34
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
1
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
5
5
Yes I get it know. It's the same reason as for
const int& a = 3; //yes
, int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.– Rick
Aug 27 at 5:03
Yes I get it know. It's the same reason as for
const int& a = 3; //yes
, int&a = 3; //no
. The formula is very helpful. Thanks. It merely becomes harder to recognize that when comes to pointer.– Rick
Aug 27 at 5:03
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).
const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.– StoryTeller
Aug 27 at 7:34
@SkepticalEmpiricist - It is. What's important to consider when taking in that comment is that the identity conversion also counts (though it's obviously not a very interesting case).
const int& a = 3;
materializes a temporary from a literal int prvalue, and binds a reference to it.– StoryTeller
Aug 27 at 7:34
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
@StoryTeller I still cannot fully follow, I thought I know what the identity conversion means in The Standard but I cannot put it into use trying to understand what you're saying. Can I kindly ask you to elaborate on this?
– SkepticalEmpiricist
Aug 27 at 7:44
1
1
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - I wasn't trying to be as exact as the standard is on this, but my line of thought (and explanation) tries to follow the C++17 changes to prvalues, the temporary materialization conversion and this bit about initializing references.
– StoryTeller
Aug 27 at 7:50
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
@SkepticalEmpiricist - It's simpler than that. The temporary can be materialized in all the examples. It's just that the whole of [dcl.init.ref]/5 doesn't define the meaning of such an initialization. So the program is ill-formed.
– StoryTeller
Aug 27 at 8:17
 |Â
show 8 more comments
up vote
6
down vote
Some additional phrasing for the bored, after reading the superb answer by StoryTeller, as I had to go through a different thought process about this.
So syntactically, In both lines we define a reference a
, and in both we shall have a materialization of a temporary pointer that takes the address of the string literal. The only difference between the two is the 2nd const
appearing only here:
const char* const & a = "hello";
and not here:
const char*& a = "hello";
This 2nd const
denotes that the object being referenced here, a pointer in this case, is itself const, as in it cannot be modified using this reference.
Hence, because the type of this string literal is const char[6]
(and not const char *
for example), our lvalue
reference to type const char*
in the second line cannot bind to it -- but the reference in the first line, being a reference to type const char* const
could. Why? Because of the rules of reference initialization:
[A reference to type “cv1 T1†is initialized by an expression of type “cv2 T2†as follows: ...]
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2
As in, our T in this quoted text is const char*
, and only in the first line it is cv-qualified no less than our object
. i.e. const char[6]
has the semantics of a const pointer, as opposed to just pointer to const.
The Clang error for the second line, read with that in mind, tells us exactly this:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
The part about being non-const lvalue reference is exactly that -- the lvalue in our case is a pointer to const
, but itself isn't const! Unlike the first line.
For this exact reason, this can compiles error-free:
char* const & a = "hello";
ISO C++11 warning aside, a compiler lets this one pass (not that it should, as the string literal is a 'const char [6]' and we shouldn't be dropping this first const
), as the reference is now const
with regards to its object, the pointer.
Another interesting thing is that An rvalue
reference const char* && a
(no "2nd const
") could bind to the temporary pointer that has materialized from the string literal, as StoryTeller provided himself. Why is that? Because of the rules of array to pointer conversion:
An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to a prvalue of type "pointer to T".
No mention of const
or other cv-qualification phrasing in here, but this stands only as long as we're initializing an rvalue ref.
add a comment |Â
up vote
6
down vote
Some additional phrasing for the bored, after reading the superb answer by StoryTeller, as I had to go through a different thought process about this.
So syntactically, In both lines we define a reference a
, and in both we shall have a materialization of a temporary pointer that takes the address of the string literal. The only difference between the two is the 2nd const
appearing only here:
const char* const & a = "hello";
and not here:
const char*& a = "hello";
This 2nd const
denotes that the object being referenced here, a pointer in this case, is itself const, as in it cannot be modified using this reference.
Hence, because the type of this string literal is const char[6]
(and not const char *
for example), our lvalue
reference to type const char*
in the second line cannot bind to it -- but the reference in the first line, being a reference to type const char* const
could. Why? Because of the rules of reference initialization:
[A reference to type “cv1 T1†is initialized by an expression of type “cv2 T2†as follows: ...]
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2
As in, our T in this quoted text is const char*
, and only in the first line it is cv-qualified no less than our object
. i.e. const char[6]
has the semantics of a const pointer, as opposed to just pointer to const.
The Clang error for the second line, read with that in mind, tells us exactly this:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
The part about being non-const lvalue reference is exactly that -- the lvalue in our case is a pointer to const
, but itself isn't const! Unlike the first line.
For this exact reason, this can compiles error-free:
char* const & a = "hello";
ISO C++11 warning aside, a compiler lets this one pass (not that it should, as the string literal is a 'const char [6]' and we shouldn't be dropping this first const
), as the reference is now const
with regards to its object, the pointer.
Another interesting thing is that An rvalue
reference const char* && a
(no "2nd const
") could bind to the temporary pointer that has materialized from the string literal, as StoryTeller provided himself. Why is that? Because of the rules of array to pointer conversion:
An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to a prvalue of type "pointer to T".
No mention of const
or other cv-qualification phrasing in here, but this stands only as long as we're initializing an rvalue ref.
add a comment |Â
up vote
6
down vote
up vote
6
down vote
Some additional phrasing for the bored, after reading the superb answer by StoryTeller, as I had to go through a different thought process about this.
So syntactically, In both lines we define a reference a
, and in both we shall have a materialization of a temporary pointer that takes the address of the string literal. The only difference between the two is the 2nd const
appearing only here:
const char* const & a = "hello";
and not here:
const char*& a = "hello";
This 2nd const
denotes that the object being referenced here, a pointer in this case, is itself const, as in it cannot be modified using this reference.
Hence, because the type of this string literal is const char[6]
(and not const char *
for example), our lvalue
reference to type const char*
in the second line cannot bind to it -- but the reference in the first line, being a reference to type const char* const
could. Why? Because of the rules of reference initialization:
[A reference to type “cv1 T1†is initialized by an expression of type “cv2 T2†as follows: ...]
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2
As in, our T in this quoted text is const char*
, and only in the first line it is cv-qualified no less than our object
. i.e. const char[6]
has the semantics of a const pointer, as opposed to just pointer to const.
The Clang error for the second line, read with that in mind, tells us exactly this:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
The part about being non-const lvalue reference is exactly that -- the lvalue in our case is a pointer to const
, but itself isn't const! Unlike the first line.
For this exact reason, this can compiles error-free:
char* const & a = "hello";
ISO C++11 warning aside, a compiler lets this one pass (not that it should, as the string literal is a 'const char [6]' and we shouldn't be dropping this first const
), as the reference is now const
with regards to its object, the pointer.
Another interesting thing is that An rvalue
reference const char* && a
(no "2nd const
") could bind to the temporary pointer that has materialized from the string literal, as StoryTeller provided himself. Why is that? Because of the rules of array to pointer conversion:
An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to a prvalue of type "pointer to T".
No mention of const
or other cv-qualification phrasing in here, but this stands only as long as we're initializing an rvalue ref.
Some additional phrasing for the bored, after reading the superb answer by StoryTeller, as I had to go through a different thought process about this.
So syntactically, In both lines we define a reference a
, and in both we shall have a materialization of a temporary pointer that takes the address of the string literal. The only difference between the two is the 2nd const
appearing only here:
const char* const & a = "hello";
and not here:
const char*& a = "hello";
This 2nd const
denotes that the object being referenced here, a pointer in this case, is itself const, as in it cannot be modified using this reference.
Hence, because the type of this string literal is const char[6]
(and not const char *
for example), our lvalue
reference to type const char*
in the second line cannot bind to it -- but the reference in the first line, being a reference to type const char* const
could. Why? Because of the rules of reference initialization:
[A reference to type “cv1 T1†is initialized by an expression of type “cv2 T2†as follows: ...]
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2
As in, our T in this quoted text is const char*
, and only in the first line it is cv-qualified no less than our object
. i.e. const char[6]
has the semantics of a const pointer, as opposed to just pointer to const.
The Clang error for the second line, read with that in mind, tells us exactly this:
error: non-const lvalue reference to type 'const char *' cannot bind to a value of unrelated type 'const char [6]'
const char*& a = "hello";
^ ~~~~~~~
The part about being non-const lvalue reference is exactly that -- the lvalue in our case is a pointer to const
, but itself isn't const! Unlike the first line.
For this exact reason, this can compiles error-free:
char* const & a = "hello";
ISO C++11 warning aside, a compiler lets this one pass (not that it should, as the string literal is a 'const char [6]' and we shouldn't be dropping this first const
), as the reference is now const
with regards to its object, the pointer.
Another interesting thing is that An rvalue
reference const char* && a
(no "2nd const
") could bind to the temporary pointer that has materialized from the string literal, as StoryTeller provided himself. Why is that? Because of the rules of array to pointer conversion:
An lvalue or rvalue of type "array of N T" or "array of unknown bound
of T" can be converted to a prvalue of type "pointer to T".
No mention of const
or other cv-qualification phrasing in here, but this stands only as long as we're initializing an rvalue ref.
edited 1 hour ago
answered Aug 27 at 4:55
SkepticalEmpiricist
2,591720
2,591720
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52032645%2fwhy-can-const-char-const-hello-compile%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password