What is the point of a constraint expression on a non-templated function?What is a lambda expression in C++11?Function template signaturesWhy does the order of template argument substitution matter?What are constrained templates?Specifying a concept for a type that has a member function template using Concepts LiteMust template argument functions be treated as potentially constexpr?Reference as a non-type template argumentPointer to function vs function as template non-type parameterWith P1141R1 voted in, how many types are deduced from multiple deduced parameters with the same constraint?What is the purpose of the declaration “template auto A::f(int t) -> decltype(t + g())”
What details should I consider before agreeing for part of my salary to be 'retained' by employer?
At which point can a system be compromised when downloading archived data from an untrusted source?
How possible is a successful landing just with 1 wing?
Improve quality of image bars
Did 007 exist before James Bond?
Why doesn't philosophy have higher standards for its arguments?
Vienna To Graz By Rail
What is the meaning of [[:space:]] in bash?
Kepler space telescope undetected planets
How to remove the first colon ':' from a timestamp?
Is it rude to refer to janitors as 'floor people'?
How to have a continuous player experience in a setting that's likely to favor TPKs?
How can a drink contain 1.8 kcal energy while 0 g fat/carbs/protein?
How many bits in the resultant hash will change, if the x bits are changed in its the original input?
Interviewing with an unmentioned 9 months of sick leave taken during a job
Increasing muscle power without increasing volume
Is passive Investigation essentially truesight against illusions?
Does the Intel 8085 CPU use real memory addresses?
Should I be able to keep my company purchased standing desk when I leave my job?
How can electric field be defined as force per charge, if the charge makes its own, singular electric field?
How could a medieval fortress manage large groups of migrants and travelers?
Intel 8080-based home computers
Alternator dying so junk car?
Why do so many pure math PhD students drop out or leave academia, compared to applied mathematics PhDs?
What is the point of a constraint expression on a non-templated function?
What is a lambda expression in C++11?Function template signaturesWhy does the order of template argument substitution matter?What are constrained templates?Specifying a concept for a type that has a member function template using Concepts LiteMust template argument functions be treated as potentially constexpr?Reference as a non-type template argumentPointer to function vs function as template non-type parameterWith P1141R1 voted in, how many types are deduced from multiple deduced parameters with the same constraint?What is the purpose of the declaration “template auto A::f(int t) -> decltype(t + g())”
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
[temp.constr.decl] says that we can constrain a template or a function with a constraint expression.
Declarators [dcl.decl] tells us that, for functions, we may add an optional trailing requires clause to constrain it, and the standard draft n4820 even gives these (seemingly pointless) examples:
void f1(int a) requires true;
auto f2(int a) -> bool requires true;
I understand that constraining a template or a concept is useful, but I fail to see how these constraints are useful for non-templated functions. What's the point of constraining a non-templated function?
c++ language-lawyer c++20
add a comment |
[temp.constr.decl] says that we can constrain a template or a function with a constraint expression.
Declarators [dcl.decl] tells us that, for functions, we may add an optional trailing requires clause to constrain it, and the standard draft n4820 even gives these (seemingly pointless) examples:
void f1(int a) requires true;
auto f2(int a) -> bool requires true;
I understand that constraining a template or a concept is useful, but I fail to see how these constraints are useful for non-templated functions. What's the point of constraining a non-templated function?
c++ language-lawyer c++20
add a comment |
[temp.constr.decl] says that we can constrain a template or a function with a constraint expression.
Declarators [dcl.decl] tells us that, for functions, we may add an optional trailing requires clause to constrain it, and the standard draft n4820 even gives these (seemingly pointless) examples:
void f1(int a) requires true;
auto f2(int a) -> bool requires true;
I understand that constraining a template or a concept is useful, but I fail to see how these constraints are useful for non-templated functions. What's the point of constraining a non-templated function?
c++ language-lawyer c++20
[temp.constr.decl] says that we can constrain a template or a function with a constraint expression.
Declarators [dcl.decl] tells us that, for functions, we may add an optional trailing requires clause to constrain it, and the standard draft n4820 even gives these (seemingly pointless) examples:
void f1(int a) requires true;
auto f2(int a) -> bool requires true;
I understand that constraining a template or a concept is useful, but I fail to see how these constraints are useful for non-templated functions. What's the point of constraining a non-templated function?
c++ language-lawyer c++20
c++ language-lawyer c++20
asked 8 hours ago
AndyGAndyG
28.1k7 gold badges74 silver badges106 bronze badges
28.1k7 gold badges74 silver badges106 bronze badges
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
One of the main points of constraining non-template functions is to be able to write constraints to non-template members of template classes. For example, you might have some type like this:
template<typename T>
class value
public:
value(const T& t);
value(T&& t);
private:
T t_;
;
Now, you want value
to be copyable/moveable from T
. But really, you want it to be copyable/moveable from T
only as far as T
itself is copyable/moveable. So, how do you do it?
Pre-constraints, you would need to write a bunch of meta-programming hackery. Maybe you make these constructors templates, which require that the given type U
is the same as T
, in addition to the copy/move requirement. Or you might have to write a base class that you inherit from, which has different specializations based on the copy/moveability of T
.
Post-constraints, you do this:
class value
public:
value(const T& t) requires is_copy_constructible_v<T> : t_(t)
value(T&& t) requires is_move_constructible_v<T> : t_(std::move(t))
private:
T t_;
;
No hackery. No applying templates to functions that don't need to be templates. It just works, and its easy for the user to understand what is going on.
This is especially important for functions which cannot be templates. In order for a constructor to be considered a copy or move constructor, it cannot be a template. Same goes for copy/move assignment operators. But such things can have constraints.
add a comment |
Just as a concept consider the following example
#include <iostream>
void f( long x ) requires ( sizeof( long ) == sizeof( int ) )
std::cout << "Bye " << x << 'n';
void f( long long x ) requires ( sizeof( long ) == sizeof( long long ) )
std::cout << "Hello " << x << 'n';
int main()
f( 0l );
If sizeof( long ) == sizeof( long long )
then the program output will be
Hello 0
Otherwise
Bye 0
For example you can use such an approach in a function that calculates the factorial to restrict the number of a loop iterations or to throw an exception.
Here is a demonstrative program.
#include <iostream>
#include <stdexcept>
unsigned long factorial( unsigned long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned int ) )
const unsigned long MAX_STEPS = 12;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
unsigned long long factorial( unsigned long long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned long long ) )
const unsigned long long MAX_STEPS = 20;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
int main()
unsigned long n = 20;
try
std::cout << factorial( n ) << 'n';
catch ( const std::out_of_range &ex )
std::cout << ex.what() << 'n';
Its output might be either
2432902008176640000
or
Too big value.
1
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
1
Indeed, or choose to write an overload instead ofif constexpr
– AndyG
8 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
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%2f57078643%2fwhat-is-the-point-of-a-constraint-expression-on-a-non-templated-function%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
One of the main points of constraining non-template functions is to be able to write constraints to non-template members of template classes. For example, you might have some type like this:
template<typename T>
class value
public:
value(const T& t);
value(T&& t);
private:
T t_;
;
Now, you want value
to be copyable/moveable from T
. But really, you want it to be copyable/moveable from T
only as far as T
itself is copyable/moveable. So, how do you do it?
Pre-constraints, you would need to write a bunch of meta-programming hackery. Maybe you make these constructors templates, which require that the given type U
is the same as T
, in addition to the copy/move requirement. Or you might have to write a base class that you inherit from, which has different specializations based on the copy/moveability of T
.
Post-constraints, you do this:
class value
public:
value(const T& t) requires is_copy_constructible_v<T> : t_(t)
value(T&& t) requires is_move_constructible_v<T> : t_(std::move(t))
private:
T t_;
;
No hackery. No applying templates to functions that don't need to be templates. It just works, and its easy for the user to understand what is going on.
This is especially important for functions which cannot be templates. In order for a constructor to be considered a copy or move constructor, it cannot be a template. Same goes for copy/move assignment operators. But such things can have constraints.
add a comment |
One of the main points of constraining non-template functions is to be able to write constraints to non-template members of template classes. For example, you might have some type like this:
template<typename T>
class value
public:
value(const T& t);
value(T&& t);
private:
T t_;
;
Now, you want value
to be copyable/moveable from T
. But really, you want it to be copyable/moveable from T
only as far as T
itself is copyable/moveable. So, how do you do it?
Pre-constraints, you would need to write a bunch of meta-programming hackery. Maybe you make these constructors templates, which require that the given type U
is the same as T
, in addition to the copy/move requirement. Or you might have to write a base class that you inherit from, which has different specializations based on the copy/moveability of T
.
Post-constraints, you do this:
class value
public:
value(const T& t) requires is_copy_constructible_v<T> : t_(t)
value(T&& t) requires is_move_constructible_v<T> : t_(std::move(t))
private:
T t_;
;
No hackery. No applying templates to functions that don't need to be templates. It just works, and its easy for the user to understand what is going on.
This is especially important for functions which cannot be templates. In order for a constructor to be considered a copy or move constructor, it cannot be a template. Same goes for copy/move assignment operators. But such things can have constraints.
add a comment |
One of the main points of constraining non-template functions is to be able to write constraints to non-template members of template classes. For example, you might have some type like this:
template<typename T>
class value
public:
value(const T& t);
value(T&& t);
private:
T t_;
;
Now, you want value
to be copyable/moveable from T
. But really, you want it to be copyable/moveable from T
only as far as T
itself is copyable/moveable. So, how do you do it?
Pre-constraints, you would need to write a bunch of meta-programming hackery. Maybe you make these constructors templates, which require that the given type U
is the same as T
, in addition to the copy/move requirement. Or you might have to write a base class that you inherit from, which has different specializations based on the copy/moveability of T
.
Post-constraints, you do this:
class value
public:
value(const T& t) requires is_copy_constructible_v<T> : t_(t)
value(T&& t) requires is_move_constructible_v<T> : t_(std::move(t))
private:
T t_;
;
No hackery. No applying templates to functions that don't need to be templates. It just works, and its easy for the user to understand what is going on.
This is especially important for functions which cannot be templates. In order for a constructor to be considered a copy or move constructor, it cannot be a template. Same goes for copy/move assignment operators. But such things can have constraints.
One of the main points of constraining non-template functions is to be able to write constraints to non-template members of template classes. For example, you might have some type like this:
template<typename T>
class value
public:
value(const T& t);
value(T&& t);
private:
T t_;
;
Now, you want value
to be copyable/moveable from T
. But really, you want it to be copyable/moveable from T
only as far as T
itself is copyable/moveable. So, how do you do it?
Pre-constraints, you would need to write a bunch of meta-programming hackery. Maybe you make these constructors templates, which require that the given type U
is the same as T
, in addition to the copy/move requirement. Or you might have to write a base class that you inherit from, which has different specializations based on the copy/moveability of T
.
Post-constraints, you do this:
class value
public:
value(const T& t) requires is_copy_constructible_v<T> : t_(t)
value(T&& t) requires is_move_constructible_v<T> : t_(std::move(t))
private:
T t_;
;
No hackery. No applying templates to functions that don't need to be templates. It just works, and its easy for the user to understand what is going on.
This is especially important for functions which cannot be templates. In order for a constructor to be considered a copy or move constructor, it cannot be a template. Same goes for copy/move assignment operators. But such things can have constraints.
answered 8 hours ago
Nicol BolasNicol Bolas
302k37 gold badges506 silver badges682 bronze badges
302k37 gold badges506 silver badges682 bronze badges
add a comment |
add a comment |
Just as a concept consider the following example
#include <iostream>
void f( long x ) requires ( sizeof( long ) == sizeof( int ) )
std::cout << "Bye " << x << 'n';
void f( long long x ) requires ( sizeof( long ) == sizeof( long long ) )
std::cout << "Hello " << x << 'n';
int main()
f( 0l );
If sizeof( long ) == sizeof( long long )
then the program output will be
Hello 0
Otherwise
Bye 0
For example you can use such an approach in a function that calculates the factorial to restrict the number of a loop iterations or to throw an exception.
Here is a demonstrative program.
#include <iostream>
#include <stdexcept>
unsigned long factorial( unsigned long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned int ) )
const unsigned long MAX_STEPS = 12;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
unsigned long long factorial( unsigned long long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned long long ) )
const unsigned long long MAX_STEPS = 20;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
int main()
unsigned long n = 20;
try
std::cout << factorial( n ) << 'n';
catch ( const std::out_of_range &ex )
std::cout << ex.what() << 'n';
Its output might be either
2432902008176640000
or
Too big value.
1
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
1
Indeed, or choose to write an overload instead ofif constexpr
– AndyG
8 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
add a comment |
Just as a concept consider the following example
#include <iostream>
void f( long x ) requires ( sizeof( long ) == sizeof( int ) )
std::cout << "Bye " << x << 'n';
void f( long long x ) requires ( sizeof( long ) == sizeof( long long ) )
std::cout << "Hello " << x << 'n';
int main()
f( 0l );
If sizeof( long ) == sizeof( long long )
then the program output will be
Hello 0
Otherwise
Bye 0
For example you can use such an approach in a function that calculates the factorial to restrict the number of a loop iterations or to throw an exception.
Here is a demonstrative program.
#include <iostream>
#include <stdexcept>
unsigned long factorial( unsigned long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned int ) )
const unsigned long MAX_STEPS = 12;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
unsigned long long factorial( unsigned long long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned long long ) )
const unsigned long long MAX_STEPS = 20;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
int main()
unsigned long n = 20;
try
std::cout << factorial( n ) << 'n';
catch ( const std::out_of_range &ex )
std::cout << ex.what() << 'n';
Its output might be either
2432902008176640000
or
Too big value.
1
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
1
Indeed, or choose to write an overload instead ofif constexpr
– AndyG
8 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
add a comment |
Just as a concept consider the following example
#include <iostream>
void f( long x ) requires ( sizeof( long ) == sizeof( int ) )
std::cout << "Bye " << x << 'n';
void f( long long x ) requires ( sizeof( long ) == sizeof( long long ) )
std::cout << "Hello " << x << 'n';
int main()
f( 0l );
If sizeof( long ) == sizeof( long long )
then the program output will be
Hello 0
Otherwise
Bye 0
For example you can use such an approach in a function that calculates the factorial to restrict the number of a loop iterations or to throw an exception.
Here is a demonstrative program.
#include <iostream>
#include <stdexcept>
unsigned long factorial( unsigned long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned int ) )
const unsigned long MAX_STEPS = 12;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
unsigned long long factorial( unsigned long long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned long long ) )
const unsigned long long MAX_STEPS = 20;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
int main()
unsigned long n = 20;
try
std::cout << factorial( n ) << 'n';
catch ( const std::out_of_range &ex )
std::cout << ex.what() << 'n';
Its output might be either
2432902008176640000
or
Too big value.
Just as a concept consider the following example
#include <iostream>
void f( long x ) requires ( sizeof( long ) == sizeof( int ) )
std::cout << "Bye " << x << 'n';
void f( long long x ) requires ( sizeof( long ) == sizeof( long long ) )
std::cout << "Hello " << x << 'n';
int main()
f( 0l );
If sizeof( long ) == sizeof( long long )
then the program output will be
Hello 0
Otherwise
Bye 0
For example you can use such an approach in a function that calculates the factorial to restrict the number of a loop iterations or to throw an exception.
Here is a demonstrative program.
#include <iostream>
#include <stdexcept>
unsigned long factorial( unsigned long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned int ) )
const unsigned long MAX_STEPS = 12;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
unsigned long long factorial( unsigned long long n ) noexcept( false )
requires ( sizeof( unsigned long ) == sizeof( unsigned long long ) )
const unsigned long long MAX_STEPS = 20;
if ( MAX_STEPS < n ) throw std::out_of_range( "Too big value." );
unsigned long f = 1;
for ( unsigned long long i = 1; i < n; i++ ) f *= ( i + 1 );
return f;
int main()
unsigned long n = 20;
try
std::cout << factorial( n ) << 'n';
catch ( const std::out_of_range &ex )
std::cout << ex.what() << 'n';
Its output might be either
2432902008176640000
or
Too big value.
edited 7 hours ago
answered 8 hours ago
Vlad from MoscowVlad from Moscow
145k13 gold badges88 silver badges186 bronze badges
145k13 gold badges88 silver badges186 bronze badges
1
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
1
Indeed, or choose to write an overload instead ofif constexpr
– AndyG
8 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
add a comment |
1
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
1
Indeed, or choose to write an overload instead ofif constexpr
– AndyG
8 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
1
1
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
Very nice. Now we can uplift static asserts out of the function body and make it part of the signature.
– NathanOliver
8 hours ago
1
1
Indeed, or choose to write an overload instead of
if constexpr
– AndyG
8 hours ago
Indeed, or choose to write an overload instead of
if constexpr
– AndyG
8 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
I wish I could accept both answers because they're of such high quality, but I felt that NicolBolas' answer was more in line with what the feature is for. I'm sorry that you'll just have to settle for an upvote.
– AndyG
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
@AndyG No problem. You are welcome.:)
– Vlad from Moscow
6 hours ago
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%2f57078643%2fwhat-is-the-point-of-a-constraint-expression-on-a-non-templated-function%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