Using ReSharper with C++17, and I enabled many of the warnings just to see what my project warns me about. I get this:
Declaring a parameter with a default argument is disallowed[fuchsia-default-arguments]
The code in question is the constructor:
class Point2D
{
public:
explicit Point2D(double x = 0.0, double y = 0.0);
};
I'm wondering why default arguments would be considered bad/poor/worthy of a warning? Does anyone have any code examples proving this a viable warning?
Here is the documentation.
There are several odd corner cases when it comes to default arguments on function parameters.
Here is a presentation from CppCon 2017 detailing a lot of tricky behavior. https://youtu.be/NeJ85q1qddQ
To summarize the main points:
Redeclarations cause potentially confusing behavior
The default arguments used in virtual function calls are not determined by the function called, but by the static type.
Default arguments on function templates can potentially look ill-formed, but may compile as long as they are not instantiated.
Of course, for your case of a non-template constructor, they are fairly innocuous. It can’t be overridden or redeclared (although an out-of-line definition might cause you possible pain).
Related
C++11 allows functions declared with the constexpr specifier to be used in constant expressions such as template arguments. There are stringent requirements about what is allowed to be constexpr; essentially such a function encapsulates only one subexpression and nothing else. (Edit: this is relaxed in C++14 but the question stands.)
Why require the keyword at all? What is gained?
It does help in revealing the intent of an interface, but it doesn't validate that intent, by guaranteeing that a function is usable in constant expressions. After writing a constexpr function, a programmer must still:
Write a test case or otherwise ensure it's actually used in a constant expression.
Document what parameter values are valid in a constant expression context.
Contrary to revealing intent, decorating functions with constexpr may add a false sense of security since tangential syntactic constraints are checked while ignoring the central semantic constraint.
In short: Would there be any undesirable effect on the language if constexpr in function declarations were merely optional? Or would there be any effect at all on any valid program?
Preventing client code expecting more than you're promising
Say I'm writing a library and have a function in there that currently returns a constant:
awesome_lib.hpp:
inline int f() { return 4; }
If constexpr wasn't required, you - as the author of client code - might go away and do something like this:
client_app.cpp:
#include <awesome_lib.hpp>
#include <array>
std::array<int, f()> my_array; // needs CT template arg
int my_c_array[f()]; // needs CT array dimension
Then should I change f() to say return the value from a config file, your client code would break, but I'd have no idea that I'd risked breaking your code. Indeed, it might be only when you have some production issue and go to recompile that you find this additional issue frustrating your rebuilding.
By changing only the implementation of f(), I'd have effectively changed the usage that could be made of the interface.
Instead, C++11 onwards provide constexpr so I can denote that client code can have a reasonable expectation of the function remaining a constexpr, and use it as such. I'm aware of and endorsing such usage as part of my interface. Just as in C++03, the compiler continues to guarantee client code isn't built to depend on other non-constexpr functions to prevent the "unwanted/unknown dependency" scenario above; that's more than documentation - it's compile time enforcement.
It's noteworthy that this continues the C++ trend of offering better alternatives for traditional uses of preprocessor macros (consider #define F 4, and how the client programmer knows whether the lib programmer considers it fair game to change to say #define F config["f"]), with their well-known "evils" such as being outside the language's namespace/class scoping system.
Why isn't there a diagnostic for "obviously" never-const functions?
I think the confusion here is due to constexpr not proactively ensuring there is any set of arguments for which the result is actually compile-time const: rather, it requires the programmer to take responsibility for that (otherwise §7.1.5/5 in the Standard deems the program ill-formed but doesn't require the compiler to issue a diagnostic). Yes, that's unfortunate, but it doesn't remove the above utility of constexpr.
So, perhaps it's helpful to switch from the question "what's the point of constexpr" to consider "why can I compile a constexpr function that can never actually return a const value?".
Answer: because there'd be a need for exhaustive branch analysis that could involve any number of combinations. It could be excessively costly in compile time and/or memory - even beyond the capability of any imaginable hardware - to diagnose. Further, even when it is practical having to diagnose such cases accurately is a whole new can of worms for compiler writers (who have better uses for their time). There would also be implications for the program such as the definition of functions called from within the constexpr function needing to be visible when the validation was performed (and functions that function calls etc.).
Meanwhile, lack of constexpr continues to forbid use as a const value: the strictness is on the sans-constexpr side. That's useful as illustrated above.
Comparison with non-`const` member functions
constexpr prevents int x[f()] while lack of const prevents const X x; x.f(); - they're both ensuring client code doesn't hardcode unwanted dependency
in both cases, you wouldn't want the compiler to determine const[expr]-ness automatically:
you wouldn't want client code to call a member function on a const object when you can already anticipate that function will evolve to modify the observable value, breaking the client code
you wouldn't want a value used as a template parameter or array dimension if you already anticipated it later being determined at runtime
they differ in that the compiler enforces const use of other members within a const member function, but does not enforce a compile-time constant result with constexpr (due to practical compiler limitations)
When I pressed Richard Smith, a Clang author, he explained:
The constexpr keyword does have utility.
It affects when a function template specialization is instantiated (constexpr function template specializations may need to be instantiated if they're called in unevaluated contexts; the same is not true for non-constexpr functions since a call to one can never be part of a constant expression). If we removed the meaning of the keyword, we'd have to instantiate a bunch more specializations early, just in case the call happens to be a constant expression.
It reduces compilation time, by limiting the set of function calls that implementations are required to try evaluating during translation. (This matters for contexts where implementations are required to try constant expression evaluation, but it's not an error if such evaluation fails -- in particular, the initializers of objects of static storage duration.)
This all didn't seem convincing at first, but if you work through the details, things do unravel without constexpr. A function need not be instantiated until it is ODR-used, which essentially means used at runtime. What is special about constexpr functions is that they can violate this rule and require instantiation anyway.
Function instantiation is a recursive procedure. Instantiating a function results in instantiation of the functions and classes it uses, regardless of the arguments to any particular call.
If something went wrong while instantiating this dependency tree (potentially at significant expense), it would be difficult to swallow the error. Furthermore, class template instantiation can have runtime side-effects.
Given an argument-dependent compile-time function call in a function signature, overload resolution may incur instantiation of function definitions merely auxiliary to the ones in the overload set, including the functions that don't even get called. Such instantiations may have side effects including ill-formedness and runtime behavior.
It's a corner case to be sure, but bad things can happen if you don't require people to opt-in to constexpr functions.
We can live without constexpr, but in certain cases it makes the code easier and intuitive.
For example we have a class which declares an array with some reference length:
template<typename T, size_t SIZE>
struct MyArray
{
T a[SIZE];
};
Conventionally you might declare MyArray as:
int a1[100];
MyArray<decltype(*a1), sizeof(a1)/sizeof(decltype(a1[0]))> obj;
Now see how it goes with constexpr:
template<typename T, size_t SIZE>
constexpr
size_t getSize (const T (&a)[SIZE]) { return SIZE; }
int a1[100];
MyArray<decltype(*a1), getSize(a1)> obj;
In short, any function (e.g. getSize(a1)) can be used as template argument only if the compiler recognizes it as constexpr.
constexpr is also used to check the negative logic. It ensures that a given object is at compile time. Here is the reference link e.g.
int i = 5;
const int j = i; // ok, but `j` is not at compile time
constexprt int k = i; // error
Without the keyword, the compiler cannot diagnose mistakes. The compiler would not be able to tell you that the function is an invalid syntactically as aconstexpr. Although you said this provides a "false sense of security", I believe it is better to pick up these errors as early as possible.
C++11 allows functions declared with the constexpr specifier to be used in constant expressions such as template arguments. There are stringent requirements about what is allowed to be constexpr; essentially such a function encapsulates only one subexpression and nothing else. (Edit: this is relaxed in C++14 but the question stands.)
Why require the keyword at all? What is gained?
It does help in revealing the intent of an interface, but it doesn't validate that intent, by guaranteeing that a function is usable in constant expressions. After writing a constexpr function, a programmer must still:
Write a test case or otherwise ensure it's actually used in a constant expression.
Document what parameter values are valid in a constant expression context.
Contrary to revealing intent, decorating functions with constexpr may add a false sense of security since tangential syntactic constraints are checked while ignoring the central semantic constraint.
In short: Would there be any undesirable effect on the language if constexpr in function declarations were merely optional? Or would there be any effect at all on any valid program?
Preventing client code expecting more than you're promising
Say I'm writing a library and have a function in there that currently returns a constant:
awesome_lib.hpp:
inline int f() { return 4; }
If constexpr wasn't required, you - as the author of client code - might go away and do something like this:
client_app.cpp:
#include <awesome_lib.hpp>
#include <array>
std::array<int, f()> my_array; // needs CT template arg
int my_c_array[f()]; // needs CT array dimension
Then should I change f() to say return the value from a config file, your client code would break, but I'd have no idea that I'd risked breaking your code. Indeed, it might be only when you have some production issue and go to recompile that you find this additional issue frustrating your rebuilding.
By changing only the implementation of f(), I'd have effectively changed the usage that could be made of the interface.
Instead, C++11 onwards provide constexpr so I can denote that client code can have a reasonable expectation of the function remaining a constexpr, and use it as such. I'm aware of and endorsing such usage as part of my interface. Just as in C++03, the compiler continues to guarantee client code isn't built to depend on other non-constexpr functions to prevent the "unwanted/unknown dependency" scenario above; that's more than documentation - it's compile time enforcement.
It's noteworthy that this continues the C++ trend of offering better alternatives for traditional uses of preprocessor macros (consider #define F 4, and how the client programmer knows whether the lib programmer considers it fair game to change to say #define F config["f"]), with their well-known "evils" such as being outside the language's namespace/class scoping system.
Why isn't there a diagnostic for "obviously" never-const functions?
I think the confusion here is due to constexpr not proactively ensuring there is any set of arguments for which the result is actually compile-time const: rather, it requires the programmer to take responsibility for that (otherwise §7.1.5/5 in the Standard deems the program ill-formed but doesn't require the compiler to issue a diagnostic). Yes, that's unfortunate, but it doesn't remove the above utility of constexpr.
So, perhaps it's helpful to switch from the question "what's the point of constexpr" to consider "why can I compile a constexpr function that can never actually return a const value?".
Answer: because there'd be a need for exhaustive branch analysis that could involve any number of combinations. It could be excessively costly in compile time and/or memory - even beyond the capability of any imaginable hardware - to diagnose. Further, even when it is practical having to diagnose such cases accurately is a whole new can of worms for compiler writers (who have better uses for their time). There would also be implications for the program such as the definition of functions called from within the constexpr function needing to be visible when the validation was performed (and functions that function calls etc.).
Meanwhile, lack of constexpr continues to forbid use as a const value: the strictness is on the sans-constexpr side. That's useful as illustrated above.
Comparison with non-`const` member functions
constexpr prevents int x[f()] while lack of const prevents const X x; x.f(); - they're both ensuring client code doesn't hardcode unwanted dependency
in both cases, you wouldn't want the compiler to determine const[expr]-ness automatically:
you wouldn't want client code to call a member function on a const object when you can already anticipate that function will evolve to modify the observable value, breaking the client code
you wouldn't want a value used as a template parameter or array dimension if you already anticipated it later being determined at runtime
they differ in that the compiler enforces const use of other members within a const member function, but does not enforce a compile-time constant result with constexpr (due to practical compiler limitations)
When I pressed Richard Smith, a Clang author, he explained:
The constexpr keyword does have utility.
It affects when a function template specialization is instantiated (constexpr function template specializations may need to be instantiated if they're called in unevaluated contexts; the same is not true for non-constexpr functions since a call to one can never be part of a constant expression). If we removed the meaning of the keyword, we'd have to instantiate a bunch more specializations early, just in case the call happens to be a constant expression.
It reduces compilation time, by limiting the set of function calls that implementations are required to try evaluating during translation. (This matters for contexts where implementations are required to try constant expression evaluation, but it's not an error if such evaluation fails -- in particular, the initializers of objects of static storage duration.)
This all didn't seem convincing at first, but if you work through the details, things do unravel without constexpr. A function need not be instantiated until it is ODR-used, which essentially means used at runtime. What is special about constexpr functions is that they can violate this rule and require instantiation anyway.
Function instantiation is a recursive procedure. Instantiating a function results in instantiation of the functions and classes it uses, regardless of the arguments to any particular call.
If something went wrong while instantiating this dependency tree (potentially at significant expense), it would be difficult to swallow the error. Furthermore, class template instantiation can have runtime side-effects.
Given an argument-dependent compile-time function call in a function signature, overload resolution may incur instantiation of function definitions merely auxiliary to the ones in the overload set, including the functions that don't even get called. Such instantiations may have side effects including ill-formedness and runtime behavior.
It's a corner case to be sure, but bad things can happen if you don't require people to opt-in to constexpr functions.
We can live without constexpr, but in certain cases it makes the code easier and intuitive.
For example we have a class which declares an array with some reference length:
template<typename T, size_t SIZE>
struct MyArray
{
T a[SIZE];
};
Conventionally you might declare MyArray as:
int a1[100];
MyArray<decltype(*a1), sizeof(a1)/sizeof(decltype(a1[0]))> obj;
Now see how it goes with constexpr:
template<typename T, size_t SIZE>
constexpr
size_t getSize (const T (&a)[SIZE]) { return SIZE; }
int a1[100];
MyArray<decltype(*a1), getSize(a1)> obj;
In short, any function (e.g. getSize(a1)) can be used as template argument only if the compiler recognizes it as constexpr.
constexpr is also used to check the negative logic. It ensures that a given object is at compile time. Here is the reference link e.g.
int i = 5;
const int j = i; // ok, but `j` is not at compile time
constexprt int k = i; // error
Without the keyword, the compiler cannot diagnose mistakes. The compiler would not be able to tell you that the function is an invalid syntactically as aconstexpr. Although you said this provides a "false sense of security", I believe it is better to pick up these errors as early as possible.
Code looks like:
struct Foo {
Foo(const char *);
};
Foo::Foo(const char *str = 0)
{
}
VS 2013 and gcc 4.8.0 accept such code,
while clang 3.3 reject such code with:
error: addition of default argument on redeclaration makes this constructor a default constructor
who is right from standard (C++03 and C++11) point of view?
Note:
I like clang's choice too, but I going to report bug to gcc and visual studio,
and if this is not correct from standard point of view, this helps to
convince compiler's developers to fix this issue.
GCC
I described issue here: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58194
But no luck, they suspend bug fixing untill draft become standard.
This has been discussed on the Clang mailinglist and has been submitted as a Defect Report Core Issue 1344.
From the mailinglist discussion:
The idea is that the presence of certain special members affects core
properties of a class type, like whether it's POD or trivially
copyable. Deciding these properties should not require whole-program
knowledge; it's important for us to be able to deduce them just from
the class definition. The really problematic case is turning a
"normal" constructor into a copy or move constructor by adding default
arguments, but IIRC introducing a default constructor was also
problematic.
The fix is that you should put the default argument in the initial
declaration of the constructor.
This was last discussed by WG21 at the Bloomington meeting. Notes from
there:
"Consensus: Make this ill-formed as suggested in the write-up. Core
issue 1344. Priority 0, Doug drafting."
So CWG has agreed (in principle) that this should be ill-formed.
TL;DR Clang is right whenever the defect gets fixed (not sure if that can officially only happen with C++14, or if such Committee decisions can also be done retroactively on C++11)
I would say CLANG is right. The standard says (12.1.5 for the both old and new versions of the standard):
A default constructor for a class X is a constructor of class X that can be called without an argument
Adding the default value to the only argument of the constructor definitely makes it possible to call it without arguments, thus making it a default one. Also, 8.3.6 says (emphasis mine):
A default argument expression shall be specified only in the
parameter-declaration-clause
of a function declaration <...>
You have a declaration and a definition. In your declaration you do not have a default value, while in your definition you have a default value. In fact the signature of the declaration is very similar to the signature of the definition, but not the same. I believe that strictness is a good idea, so I believe it is better to enforce that the declaration is the same as the definition.
C++11 allows functions declared with the constexpr specifier to be used in constant expressions such as template arguments. There are stringent requirements about what is allowed to be constexpr; essentially such a function encapsulates only one subexpression and nothing else. (Edit: this is relaxed in C++14 but the question stands.)
Why require the keyword at all? What is gained?
It does help in revealing the intent of an interface, but it doesn't validate that intent, by guaranteeing that a function is usable in constant expressions. After writing a constexpr function, a programmer must still:
Write a test case or otherwise ensure it's actually used in a constant expression.
Document what parameter values are valid in a constant expression context.
Contrary to revealing intent, decorating functions with constexpr may add a false sense of security since tangential syntactic constraints are checked while ignoring the central semantic constraint.
In short: Would there be any undesirable effect on the language if constexpr in function declarations were merely optional? Or would there be any effect at all on any valid program?
Preventing client code expecting more than you're promising
Say I'm writing a library and have a function in there that currently returns a constant:
awesome_lib.hpp:
inline int f() { return 4; }
If constexpr wasn't required, you - as the author of client code - might go away and do something like this:
client_app.cpp:
#include <awesome_lib.hpp>
#include <array>
std::array<int, f()> my_array; // needs CT template arg
int my_c_array[f()]; // needs CT array dimension
Then should I change f() to say return the value from a config file, your client code would break, but I'd have no idea that I'd risked breaking your code. Indeed, it might be only when you have some production issue and go to recompile that you find this additional issue frustrating your rebuilding.
By changing only the implementation of f(), I'd have effectively changed the usage that could be made of the interface.
Instead, C++11 onwards provide constexpr so I can denote that client code can have a reasonable expectation of the function remaining a constexpr, and use it as such. I'm aware of and endorsing such usage as part of my interface. Just as in C++03, the compiler continues to guarantee client code isn't built to depend on other non-constexpr functions to prevent the "unwanted/unknown dependency" scenario above; that's more than documentation - it's compile time enforcement.
It's noteworthy that this continues the C++ trend of offering better alternatives for traditional uses of preprocessor macros (consider #define F 4, and how the client programmer knows whether the lib programmer considers it fair game to change to say #define F config["f"]), with their well-known "evils" such as being outside the language's namespace/class scoping system.
Why isn't there a diagnostic for "obviously" never-const functions?
I think the confusion here is due to constexpr not proactively ensuring there is any set of arguments for which the result is actually compile-time const: rather, it requires the programmer to take responsibility for that (otherwise §7.1.5/5 in the Standard deems the program ill-formed but doesn't require the compiler to issue a diagnostic). Yes, that's unfortunate, but it doesn't remove the above utility of constexpr.
So, perhaps it's helpful to switch from the question "what's the point of constexpr" to consider "why can I compile a constexpr function that can never actually return a const value?".
Answer: because there'd be a need for exhaustive branch analysis that could involve any number of combinations. It could be excessively costly in compile time and/or memory - even beyond the capability of any imaginable hardware - to diagnose. Further, even when it is practical having to diagnose such cases accurately is a whole new can of worms for compiler writers (who have better uses for their time). There would also be implications for the program such as the definition of functions called from within the constexpr function needing to be visible when the validation was performed (and functions that function calls etc.).
Meanwhile, lack of constexpr continues to forbid use as a const value: the strictness is on the sans-constexpr side. That's useful as illustrated above.
Comparison with non-`const` member functions
constexpr prevents int x[f()] while lack of const prevents const X x; x.f(); - they're both ensuring client code doesn't hardcode unwanted dependency
in both cases, you wouldn't want the compiler to determine const[expr]-ness automatically:
you wouldn't want client code to call a member function on a const object when you can already anticipate that function will evolve to modify the observable value, breaking the client code
you wouldn't want a value used as a template parameter or array dimension if you already anticipated it later being determined at runtime
they differ in that the compiler enforces const use of other members within a const member function, but does not enforce a compile-time constant result with constexpr (due to practical compiler limitations)
When I pressed Richard Smith, a Clang author, he explained:
The constexpr keyword does have utility.
It affects when a function template specialization is instantiated (constexpr function template specializations may need to be instantiated if they're called in unevaluated contexts; the same is not true for non-constexpr functions since a call to one can never be part of a constant expression). If we removed the meaning of the keyword, we'd have to instantiate a bunch more specializations early, just in case the call happens to be a constant expression.
It reduces compilation time, by limiting the set of function calls that implementations are required to try evaluating during translation. (This matters for contexts where implementations are required to try constant expression evaluation, but it's not an error if such evaluation fails -- in particular, the initializers of objects of static storage duration.)
This all didn't seem convincing at first, but if you work through the details, things do unravel without constexpr. A function need not be instantiated until it is ODR-used, which essentially means used at runtime. What is special about constexpr functions is that they can violate this rule and require instantiation anyway.
Function instantiation is a recursive procedure. Instantiating a function results in instantiation of the functions and classes it uses, regardless of the arguments to any particular call.
If something went wrong while instantiating this dependency tree (potentially at significant expense), it would be difficult to swallow the error. Furthermore, class template instantiation can have runtime side-effects.
Given an argument-dependent compile-time function call in a function signature, overload resolution may incur instantiation of function definitions merely auxiliary to the ones in the overload set, including the functions that don't even get called. Such instantiations may have side effects including ill-formedness and runtime behavior.
It's a corner case to be sure, but bad things can happen if you don't require people to opt-in to constexpr functions.
We can live without constexpr, but in certain cases it makes the code easier and intuitive.
For example we have a class which declares an array with some reference length:
template<typename T, size_t SIZE>
struct MyArray
{
T a[SIZE];
};
Conventionally you might declare MyArray as:
int a1[100];
MyArray<decltype(*a1), sizeof(a1)/sizeof(decltype(a1[0]))> obj;
Now see how it goes with constexpr:
template<typename T, size_t SIZE>
constexpr
size_t getSize (const T (&a)[SIZE]) { return SIZE; }
int a1[100];
MyArray<decltype(*a1), getSize(a1)> obj;
In short, any function (e.g. getSize(a1)) can be used as template argument only if the compiler recognizes it as constexpr.
constexpr is also used to check the negative logic. It ensures that a given object is at compile time. Here is the reference link e.g.
int i = 5;
const int j = i; // ok, but `j` is not at compile time
constexprt int k = i; // error
Without the keyword, the compiler cannot diagnose mistakes. The compiler would not be able to tell you that the function is an invalid syntactically as aconstexpr. Although you said this provides a "false sense of security", I believe it is better to pick up these errors as early as possible.
When you use a template with numerous methods (like vector) and compile your code, will the compiler discard the code from the unused methods?
A template is not instantiated unless it is used, so there is actually no code to discard.
The standard says (14.7.1/10)
An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. The use of a template specialization in a default argument shall not cause the template to be implicitly instantiated except that a class template may be instantiated where its complete type is needed to determine the correctness of the default argument. The use of a default argument in a function call causes specializations in the default argument to be implicitly instantiated.
So if you can avoid making the template's member functions virtual, the compiler will not generate any code for them (and that might work for virtual functions as well, if the compiler is smart enough).
It depends on your optimization level. At higher optimization settings, yes, dead code elimination will most likely occur.
the compiler, optimizers, and the linker can omit and/or reduce that information. each mature tool likely has options specific to dead code elimination.
with templates, the code may not really be created in the first place (unless instantiated).
certainly not all of it will be removed in every scenario, however (rtti is a silent killer). a bit of caution and testing using your build settings can go a long way to help you reduce the binary sizes and dead code.
Smart compilers will exclude it most likely. Long time ago when I played with Borland C++ Builder, I think, it did not throw out unused template class methods. Can not confirm though