Why is `const T&` not sure to be const?
template<typename T>
void f(T a, const T& b)
{
++a; // ok
++b; // also ok!
}
template<typename T>
void g(T n)
{
f<T>(n, n);
}
int main()
{
int n{};
g<int&>(n);
}
Please note: b
is of const T&
and ++b
is ok!
Why is const T&
not sure to be const?
c++ c++11 const function-templates const-reference
add a comment |
template<typename T>
void f(T a, const T& b)
{
++a; // ok
++b; // also ok!
}
template<typename T>
void g(T n)
{
f<T>(n, n);
}
int main()
{
int n{};
g<int&>(n);
}
Please note: b
is of const T&
and ++b
is ok!
Why is const T&
not sure to be const?
c++ c++11 const function-templates const-reference
add a comment |
template<typename T>
void f(T a, const T& b)
{
++a; // ok
++b; // also ok!
}
template<typename T>
void g(T n)
{
f<T>(n, n);
}
int main()
{
int n{};
g<int&>(n);
}
Please note: b
is of const T&
and ++b
is ok!
Why is const T&
not sure to be const?
c++ c++11 const function-templates const-reference
template<typename T>
void f(T a, const T& b)
{
++a; // ok
++b; // also ok!
}
template<typename T>
void g(T n)
{
f<T>(n, n);
}
int main()
{
int n{};
g<int&>(n);
}
Please note: b
is of const T&
and ++b
is ok!
Why is const T&
not sure to be const?
c++ c++11 const function-templates const-reference
c++ c++11 const function-templates const-reference
edited Feb 2 at 3:30
curiousguy
4,63623046
4,63623046
asked Feb 1 at 13:32
xmllmxxmllmx
13.9k988212
13.9k988212
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Welcome to const and reference collapsing. When you have const T&
, the reference gets applied to T
, and so does the const
. You call g
like
g<int&>(n);
so you have specified that T
is a int&
. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& &
becomes just int&
. Then we get to the rule from [dcl.ref]/1, which states that if you apply const
to a reference it is discarded, so int& const
just becomes int&
(note that you can't actually declare int& const
, it has to come from a typedef or template). That means for
g<int&>(n);
you are actually calling
void f(int& a, int& b)
and you are not actually modifying a constant.
Had you called g
as
g<int>(n);
// or just
g(n);
then T
would be int
, and f
would have been stamped out as
void f(int a, const int& b)
Since T
isn't a reference anymore, the const
and the &
get applied to it, and you would have received a compiler error for trying to modify a constant variable.
7
This is why the type traits likestd::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.
– Mgetz
Feb 1 at 14:00
9
One way to make it easier to understand is to writeT const&
instead ofconst T&
(which is the same), and then replaceT
withint&
.
– Ruslan
Feb 1 at 15:38
I would reorder some of the first part of this answer, since in the typeconst T&
, first theconst
applies toT
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, andconst T&
would always mean the same asT&
.)
– aschepler
Feb 1 at 22:22
@aschepler The rules stopT& const
, notconst T&
/T const &
– NathanOliver
Feb 1 at 22:24
@NathanOliver I'm just suggesting discussing the effect ofconst
before the effect of lvalue-reference, sinceusing U = const T&;
means the same asusing tmp1 = const T; using U = tmp1&;
but not the same asusing tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
|
show 3 more comments
I know that there is already an accepted answer which is correct but just to add to it a little bit, even outside the realm of templates and just in function declarations in general...
( const T& )
is not the same as
( const T )
In your example which matches the first, you have a const reference. If you truly want a const value that is not modifiable remove the reference as in the second example.
8
whenT
isint&
,const T&
andconst T
both giveint&
.
– Ben Voigt
Feb 1 at 14:52
I think there was a misconception on what I was trying to say; I'm using T here not as atemplate
parameter. T was just meant to be used as any data type:int
,float
,double
etc.. soT
in my example above should never beint&
. I did specifically state outside the realm of templates.
– Francis Cugler
Feb 1 at 22:08
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
This can also be an issue with no templates involved:using T = int&; void f(const T&);
declaresvoid f(int&);
.
– aschepler
Feb 1 at 22:23
@aschepler true, but I wasn't referring tousing
clauses; just basic function declarations in general.
– Francis Cugler
Feb 2 at 0:20
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
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
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54480599%2fwhy-is-const-t-not-sure-to-be-const%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Welcome to const and reference collapsing. When you have const T&
, the reference gets applied to T
, and so does the const
. You call g
like
g<int&>(n);
so you have specified that T
is a int&
. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& &
becomes just int&
. Then we get to the rule from [dcl.ref]/1, which states that if you apply const
to a reference it is discarded, so int& const
just becomes int&
(note that you can't actually declare int& const
, it has to come from a typedef or template). That means for
g<int&>(n);
you are actually calling
void f(int& a, int& b)
and you are not actually modifying a constant.
Had you called g
as
g<int>(n);
// or just
g(n);
then T
would be int
, and f
would have been stamped out as
void f(int a, const int& b)
Since T
isn't a reference anymore, the const
and the &
get applied to it, and you would have received a compiler error for trying to modify a constant variable.
7
This is why the type traits likestd::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.
– Mgetz
Feb 1 at 14:00
9
One way to make it easier to understand is to writeT const&
instead ofconst T&
(which is the same), and then replaceT
withint&
.
– Ruslan
Feb 1 at 15:38
I would reorder some of the first part of this answer, since in the typeconst T&
, first theconst
applies toT
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, andconst T&
would always mean the same asT&
.)
– aschepler
Feb 1 at 22:22
@aschepler The rules stopT& const
, notconst T&
/T const &
– NathanOliver
Feb 1 at 22:24
@NathanOliver I'm just suggesting discussing the effect ofconst
before the effect of lvalue-reference, sinceusing U = const T&;
means the same asusing tmp1 = const T; using U = tmp1&;
but not the same asusing tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
|
show 3 more comments
Welcome to const and reference collapsing. When you have const T&
, the reference gets applied to T
, and so does the const
. You call g
like
g<int&>(n);
so you have specified that T
is a int&
. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& &
becomes just int&
. Then we get to the rule from [dcl.ref]/1, which states that if you apply const
to a reference it is discarded, so int& const
just becomes int&
(note that you can't actually declare int& const
, it has to come from a typedef or template). That means for
g<int&>(n);
you are actually calling
void f(int& a, int& b)
and you are not actually modifying a constant.
Had you called g
as
g<int>(n);
// or just
g(n);
then T
would be int
, and f
would have been stamped out as
void f(int a, const int& b)
Since T
isn't a reference anymore, the const
and the &
get applied to it, and you would have received a compiler error for trying to modify a constant variable.
7
This is why the type traits likestd::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.
– Mgetz
Feb 1 at 14:00
9
One way to make it easier to understand is to writeT const&
instead ofconst T&
(which is the same), and then replaceT
withint&
.
– Ruslan
Feb 1 at 15:38
I would reorder some of the first part of this answer, since in the typeconst T&
, first theconst
applies toT
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, andconst T&
would always mean the same asT&
.)
– aschepler
Feb 1 at 22:22
@aschepler The rules stopT& const
, notconst T&
/T const &
– NathanOliver
Feb 1 at 22:24
@NathanOliver I'm just suggesting discussing the effect ofconst
before the effect of lvalue-reference, sinceusing U = const T&;
means the same asusing tmp1 = const T; using U = tmp1&;
but not the same asusing tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
|
show 3 more comments
Welcome to const and reference collapsing. When you have const T&
, the reference gets applied to T
, and so does the const
. You call g
like
g<int&>(n);
so you have specified that T
is a int&
. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& &
becomes just int&
. Then we get to the rule from [dcl.ref]/1, which states that if you apply const
to a reference it is discarded, so int& const
just becomes int&
(note that you can't actually declare int& const
, it has to come from a typedef or template). That means for
g<int&>(n);
you are actually calling
void f(int& a, int& b)
and you are not actually modifying a constant.
Had you called g
as
g<int>(n);
// or just
g(n);
then T
would be int
, and f
would have been stamped out as
void f(int a, const int& b)
Since T
isn't a reference anymore, the const
and the &
get applied to it, and you would have received a compiler error for trying to modify a constant variable.
Welcome to const and reference collapsing. When you have const T&
, the reference gets applied to T
, and so does the const
. You call g
like
g<int&>(n);
so you have specified that T
is a int&
. When we apply a reference to an lvalue reference, the two references collapse to a single one, so int& &
becomes just int&
. Then we get to the rule from [dcl.ref]/1, which states that if you apply const
to a reference it is discarded, so int& const
just becomes int&
(note that you can't actually declare int& const
, it has to come from a typedef or template). That means for
g<int&>(n);
you are actually calling
void f(int& a, int& b)
and you are not actually modifying a constant.
Had you called g
as
g<int>(n);
// or just
g(n);
then T
would be int
, and f
would have been stamped out as
void f(int a, const int& b)
Since T
isn't a reference anymore, the const
and the &
get applied to it, and you would have received a compiler error for trying to modify a constant variable.
edited Feb 2 at 3:19
Fabio Turati
2,63452341
2,63452341
answered Feb 1 at 13:36
NathanOliverNathanOliver
95.3k16134205
95.3k16134205
7
This is why the type traits likestd::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.
– Mgetz
Feb 1 at 14:00
9
One way to make it easier to understand is to writeT const&
instead ofconst T&
(which is the same), and then replaceT
withint&
.
– Ruslan
Feb 1 at 15:38
I would reorder some of the first part of this answer, since in the typeconst T&
, first theconst
applies toT
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, andconst T&
would always mean the same asT&
.)
– aschepler
Feb 1 at 22:22
@aschepler The rules stopT& const
, notconst T&
/T const &
– NathanOliver
Feb 1 at 22:24
@NathanOliver I'm just suggesting discussing the effect ofconst
before the effect of lvalue-reference, sinceusing U = const T&;
means the same asusing tmp1 = const T; using U = tmp1&;
but not the same asusing tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
|
show 3 more comments
7
This is why the type traits likestd::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.
– Mgetz
Feb 1 at 14:00
9
One way to make it easier to understand is to writeT const&
instead ofconst T&
(which is the same), and then replaceT
withint&
.
– Ruslan
Feb 1 at 15:38
I would reorder some of the first part of this answer, since in the typeconst T&
, first theconst
applies toT
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, andconst T&
would always mean the same asT&
.)
– aschepler
Feb 1 at 22:22
@aschepler The rules stopT& const
, notconst T&
/T const &
– NathanOliver
Feb 1 at 22:24
@NathanOliver I'm just suggesting discussing the effect ofconst
before the effect of lvalue-reference, sinceusing U = const T&;
means the same asusing tmp1 = const T; using U = tmp1&;
but not the same asusing tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
7
7
This is why the type traits like
std::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.– Mgetz
Feb 1 at 14:00
This is why the type traits like
std::add_lvalue_reference
exist, to ensure that references are added in a predictable way to prevent just this sort of pain.– Mgetz
Feb 1 at 14:00
9
9
One way to make it easier to understand is to write
T const&
instead of const T&
(which is the same), and then replace T
with int&
.– Ruslan
Feb 1 at 15:38
One way to make it easier to understand is to write
T const&
instead of const T&
(which is the same), and then replace T
with int&
.– Ruslan
Feb 1 at 15:38
I would reorder some of the first part of this answer, since in the type
const T&
, first the const
applies to T
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, and const T&
would always mean the same as T&
.)– aschepler
Feb 1 at 22:22
I would reorder some of the first part of this answer, since in the type
const T&
, first the const
applies to T
, and then the lvalue-reference applies to the result of that. (If the rule were the opposite, the "const applied to a reference type is ignored" rule would always kick in, and const T&
would always mean the same as T&
.)– aschepler
Feb 1 at 22:22
@aschepler The rules stop
T& const
, not const T&
/T const &
– NathanOliver
Feb 1 at 22:24
@aschepler The rules stop
T& const
, not const T&
/T const &
– NathanOliver
Feb 1 at 22:24
@NathanOliver I'm just suggesting discussing the effect of
const
before the effect of lvalue-reference, since using U = const T&;
means the same as using tmp1 = const T; using U = tmp1&;
but not the same as using tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
@NathanOliver I'm just suggesting discussing the effect of
const
before the effect of lvalue-reference, since using U = const T&;
means the same as using tmp1 = const T; using U = tmp1&;
but not the same as using tmp2 = T&; using U = const tmp2;
– aschepler
Feb 1 at 22:30
|
show 3 more comments
I know that there is already an accepted answer which is correct but just to add to it a little bit, even outside the realm of templates and just in function declarations in general...
( const T& )
is not the same as
( const T )
In your example which matches the first, you have a const reference. If you truly want a const value that is not modifiable remove the reference as in the second example.
8
whenT
isint&
,const T&
andconst T
both giveint&
.
– Ben Voigt
Feb 1 at 14:52
I think there was a misconception on what I was trying to say; I'm using T here not as atemplate
parameter. T was just meant to be used as any data type:int
,float
,double
etc.. soT
in my example above should never beint&
. I did specifically state outside the realm of templates.
– Francis Cugler
Feb 1 at 22:08
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
This can also be an issue with no templates involved:using T = int&; void f(const T&);
declaresvoid f(int&);
.
– aschepler
Feb 1 at 22:23
@aschepler true, but I wasn't referring tousing
clauses; just basic function declarations in general.
– Francis Cugler
Feb 2 at 0:20
add a comment |
I know that there is already an accepted answer which is correct but just to add to it a little bit, even outside the realm of templates and just in function declarations in general...
( const T& )
is not the same as
( const T )
In your example which matches the first, you have a const reference. If you truly want a const value that is not modifiable remove the reference as in the second example.
8
whenT
isint&
,const T&
andconst T
both giveint&
.
– Ben Voigt
Feb 1 at 14:52
I think there was a misconception on what I was trying to say; I'm using T here not as atemplate
parameter. T was just meant to be used as any data type:int
,float
,double
etc.. soT
in my example above should never beint&
. I did specifically state outside the realm of templates.
– Francis Cugler
Feb 1 at 22:08
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
This can also be an issue with no templates involved:using T = int&; void f(const T&);
declaresvoid f(int&);
.
– aschepler
Feb 1 at 22:23
@aschepler true, but I wasn't referring tousing
clauses; just basic function declarations in general.
– Francis Cugler
Feb 2 at 0:20
add a comment |
I know that there is already an accepted answer which is correct but just to add to it a little bit, even outside the realm of templates and just in function declarations in general...
( const T& )
is not the same as
( const T )
In your example which matches the first, you have a const reference. If you truly want a const value that is not modifiable remove the reference as in the second example.
I know that there is already an accepted answer which is correct but just to add to it a little bit, even outside the realm of templates and just in function declarations in general...
( const T& )
is not the same as
( const T )
In your example which matches the first, you have a const reference. If you truly want a const value that is not modifiable remove the reference as in the second example.
answered Feb 1 at 14:17
Francis CuglerFrancis Cugler
4,81411227
4,81411227
8
whenT
isint&
,const T&
andconst T
both giveint&
.
– Ben Voigt
Feb 1 at 14:52
I think there was a misconception on what I was trying to say; I'm using T here not as atemplate
parameter. T was just meant to be used as any data type:int
,float
,double
etc.. soT
in my example above should never beint&
. I did specifically state outside the realm of templates.
– Francis Cugler
Feb 1 at 22:08
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
This can also be an issue with no templates involved:using T = int&; void f(const T&);
declaresvoid f(int&);
.
– aschepler
Feb 1 at 22:23
@aschepler true, but I wasn't referring tousing
clauses; just basic function declarations in general.
– Francis Cugler
Feb 2 at 0:20
add a comment |
8
whenT
isint&
,const T&
andconst T
both giveint&
.
– Ben Voigt
Feb 1 at 14:52
I think there was a misconception on what I was trying to say; I'm using T here not as atemplate
parameter. T was just meant to be used as any data type:int
,float
,double
etc.. soT
in my example above should never beint&
. I did specifically state outside the realm of templates.
– Francis Cugler
Feb 1 at 22:08
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
This can also be an issue with no templates involved:using T = int&; void f(const T&);
declaresvoid f(int&);
.
– aschepler
Feb 1 at 22:23
@aschepler true, but I wasn't referring tousing
clauses; just basic function declarations in general.
– Francis Cugler
Feb 2 at 0:20
8
8
when
T
is int&
, const T&
and const T
both give int&
.– Ben Voigt
Feb 1 at 14:52
when
T
is int&
, const T&
and const T
both give int&
.– Ben Voigt
Feb 1 at 14:52
I think there was a misconception on what I was trying to say; I'm using T here not as a
template
parameter. T was just meant to be used as any data type: int
, float
, double
etc.. so T
in my example above should never be int&
. I did specifically state outside the realm of templates.– Francis Cugler
Feb 1 at 22:08
I think there was a misconception on what I was trying to say; I'm using T here not as a
template
parameter. T was just meant to be used as any data type: int
, float
, double
etc.. so T
in my example above should never be int&
. I did specifically state outside the realm of templates.– Francis Cugler
Feb 1 at 22:08
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
Hmm, it sounds as if you are explaining that you can see this without templates, which is no problem. But then your final sentence claims to offer a solution to OP's problem, and that problem definitely involves templates. It's fine to offer a solution to a template question which is broader than just templates. But a solution to a template question that isn't accurate for templates, seems not to answer the question.
– Ben Voigt
Feb 1 at 22:16
This can also be an issue with no templates involved:
using T = int&; void f(const T&);
declares void f(int&);
.– aschepler
Feb 1 at 22:23
This can also be an issue with no templates involved:
using T = int&; void f(const T&);
declares void f(int&);
.– aschepler
Feb 1 at 22:23
@aschepler true, but I wasn't referring to
using
clauses; just basic function declarations in general.– Francis Cugler
Feb 2 at 0:20
@aschepler true, but I wasn't referring to
using
clauses; just basic function declarations in general.– Francis Cugler
Feb 2 at 0:20
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54480599%2fwhy-is-const-t-not-sure-to-be-const%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
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
Required, but never shown
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
Required, but never shown
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
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown