I have some utility code that I've been using for years to safely call the ctype family of functions, it looks like this:
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
And is used like this:
int r = safe_ctype<std::isspace>(ch);
The idea being that it handles the need to cast the input int to an unsigned value for you in order to prevent undefined behavior. The specifics of this function is somewhat irrelivant though. Here's my question:
Now that in C++17 and later, noexcept is part of the type system, this is a compile error! Because all of the ctype functions are now noexcept.
EDIT: The above sentence is incorrect. the ctype family of functions are not noexcept. I was however getting a compiler error in gcc < 11.2. https://godbolt.org/z/cTq94q5xE
The code works as expected (despite being technically not allowed due to these functions not being addressable) with the latest versions of all 3 major compilers.
I can of course change my function to look like this:
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
But now it doesn't work when compiled as C++11 or C++14. So I end up having to do something like this:
#if __cplusplus >= 201703L
template<int (&F)(int) noexcept>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
#else
template<int (&F)(int)>
int safe_ctype(unsigned char c) {
return F(c);
}
#endif
Which is getting increasingly complex for such a simple task. So is there a way to make the function pointer:
valid for C++11 - C++20
Accept both noexcept and non-noexcept when in C++17+
?
I tried doing something like this:
template<class F>
int safe_ctype(unsigned char c) noexcept {
return F(c);
}
In the hopes that it would accept "anything", but sadly, no go.
Thoughts?
Now that in C++17 and later, noexcept is part of the type system, this is a compile error! Because all of the ctype functions are now noexcept.
It is not a compile error. Pointers to noexcept functions are implicitly convertible to pointers to potentially throwing functions, and thus the template accepting a pointer to potentially throwing functions works with both potentially throwing and noexcept functions. Only caveat is that the noexceptedness information is lost and might not be used for optimisation purposes.
Hence, the original solution satisfies both points 1. and 2.
Another problem pointed out in the comments is that the standard library functions (std::isspace) that you intend to use are not designated "addressable". Hence the behaviour of the program is unspecified (possibly ill-formed) due to forming a pointer to them.
To wrap such callable, you could use a lambda instead of a function pointer. But that makes the template itself obsolete since you can change the argument type of the lambda directly:
auto safe_isspace = [](unsigned char c){ return std::isspace(c); };
int r = safe_isspace(ch);
Though we no longer need to pass this into a template, so the same can be achieved with a plain function:
int // or bool?
safe_isspace(unsigned char c) noexcept // ...
Since this involves a bit of identical boilerplate for multiple functions, this is a good candidate for meta-programming.
Because all of the ctype functions are now noexcept.
This is untrue. C++17 did not add noexcept to any C-library functions accessed through the C++ c* headers. You can see here that all of the C++ function declarations do not contain noexcept. And a standard library implementation is not allowed to make non-noexcept functions noexcept.
Secondly, even if it were noexcept, a noexcept function pointer can be converted into a throwing function pointer (but not the other way around). So your code compiles.
But most importantly, C++20 makes it clear that you are not allowed to get function pointers for any C++ standard library function unless it is specifically stated to be "addressable". And there are very few addressable functions in the C++ standard library.
So in C++20, your code will yield UB. You're just going to have to write wrappers for the cctype functions if you want your code to work across all language versions.
Related
While writing a custom reflection library I encountered a strange compiler behavior. However I was able to reproduce the problem with a much simplified code. Here is:
#include <iostream>
class OtherBase{};
class Base{};
/* Used only as a test class to verify if the reflection API works properly*/
class Derived : Base, OtherBase
{
public:
void Printer()
{
std::cout << "Derived::Printer() has been called" << std::endl;
}
};
/*Descriptor class that basically incapsulate the address of Derived::Printer method*/
struct ClassDescriptor
{
using type = Derived;
struct FuncDescriptor
{
static constexpr const auto member_address{ &type::Printer };
};
};
int main()
{
Derived derived;
auto address{ &Derived::Printer };
(derived.*address)(); // -> OK it compiles fine using the local variable address
(derived.*ClassDescriptor::FuncDescriptor::member_address)(); // -> BROKEN using the address from the descriptor class cause fatal error C1001 !
}
While trying debugging this problem I noticed that:
It happen only if Derived has multiple inheritance.
If I swap static constexpr const auto member_address{ &type::Printer } with inline static const auto member_address{ &type::Printer } it works.
Is it just a compiler bug, or I'm doing something wrong ?
Can I solve this problem while keeping the constexpr ?
Please note that I'm using MSVC 2017 with the compiler version 19.16.27024.1
All compiler options are default except for /std:c++17 enabled.
I know that updating (and surely i'll do it) the compiler version to the last one will probably solve the issue, but for now I would like to understand more about this problem.
About C1001, Microsoft Developer Network suggests that you remove some optimizations in your code: Fatal Error C1001. Once you've worked out which optimization is causing the issue, you can use a #pragma to disable that optimization in just that area:
// Disable the optimization
#pragma optimize( "", off )
...
// Re-enable any previous optimization
#pragma optimize( "", on )
Also, a fix for this issue has been released by Microsoft. You could install the most recent release.
const and constexpr:
const declares an object as constant. This implies a guarantee that once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization.
constexpr declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr is not the only way to do this.
When applied to functions the basic difference is this:
const can only be used for non-static member functions, not functions in general. It gives a guarantee that the member function does not modify any of the non-static data members.
constexpr can be used with both member and non-member functions, as well as constructors. It declares the function fit for use in constant expressions. The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly:
The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single return statement is allowed. In the case of a constructor, only an initialization list, typedefs, and static assert are allowed. (= default and = delete are allowed, too, though.)
As of C++14, the rules are more relaxed, what is allowed since then inside a constexpr function: asm declaration, a goto statement, a statement with a label other than case and default, try-block, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the definition of a variable for which no initialization is performed.
The arguments and the return type must be literal types (i.e., generally speaking, very simple types, typically scalars or aggregates)
When can I / should I use both, const and constexpr together?
A. In object declarations. This is never necessary when both keywords refer to the same object to be declared. constexpr implies const.
constexpr const int N = 5;
is the same as
constexpr int N = 5;
However, note that there may be situations when the keywords each refer to different parts of the declaration:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}
Here, NP is declared as an address constant-expression, i.e. a pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both constexpr and const are required: constexpr always refers to the expression being declared (here NP), while const refers to int (it declares a pointer-to-const). Removing the const would render the expression illegal (because (a) a pointer to a non-const object cannot be a constant expression, and (b) &N is in-fact a pointer-to-constant).
B. In member function declarations. In C++11, constexpr implies const, while in C++14 and C++17 that is not the case. A member function declared under C++11 as
constexpr void f();
needs to be declared as
constexpr void f() const;
under C++14 in order to still be usable as a const function.
You could refer to this link for more details.
The auto keyword can be used in many contexts and combined with other language elements, as in const auto& or auto&&. However, it cannot be used in cast operations. Consider the following example (which does not compile):
template <class T> void foo(T&& t) {}
int main() {
int i = 0;
foo(static_cast<const auto&>(i)); // This could call foo(const int&)
}
The cast would obviously work with int instead of auto, but being able to use auto in casts would be useful in generic code, for instance:
You could use const auto& (as above) to explicitly call an overloaded function with a const lvalue ref.
Similarly, you could use static_cast<auto&&> as a less verbose version of std::forward<decltype(x)>(x).
Thinking a bit further, static_cast<auto>(x) or something like auto(x) could be a way of explicitly copying an object.
(Note that explicit types instead of auto can be used in all these scenarios.)
To be honest, I intuitively expected this syntax to work (because it mirrors the way auto can be used in declarations), but to my mild surprise it didn't. Since it is such an obvious syntax, I am wondering whether there are specific reasons why it is disallowed? Or is it simply a case of nobody considering/proposing it as a feature?
I got a wrapper class that has a simple and light-weighted implicit conversion operator to double.
I like to use it as I would use a double, for example:
if (!std::isfinite(myVar)) ...
But visual c++ implementation of std::isfinite(double) is actually a template that get his argument by copy.
So my wrapper class copy constructor is called, and it is not light-weighted.
To avoid this, I have to write:
if (!std::isfinite((double)myVar)) ...
for every call :(
If visual c++ std::isfinite() was defined as is it on cppreference.com, I would not have to cast every call: ([edit] I may be wrong, Integral isn't an actual type... but... [edit] It still should not accept user defined types ?)
bool isfinite( float arg );
bool isfinite( double arg );
bool isfinite( long double arg );
bool isfinite( Integral arg );
I am not sure what the standard says about this.
Is vc++ template std::isfinite standard-conforming ?
Should I report this as a bug on Microsoft connect ?
Should I define my own isfinite(double) that calls std::isfinite ?
edit
Or maybe it is a non-issue as in a release build the calls get inlined and no copy occurs ? (well I'll try to check it right now and update in a few minutes)
edit 2
It doesn't seem to get inlined in a release build with /Ob2 (inline any suitable function)
edit 3
as requested, a sample:
struct DoubleWrapper {
double value;
DoubleWrapper(double value) : value(value) {
printf("copy Ctor\n");
}
DoubleWrapper(const DoubleWrapper & that) : value(that.value) {}
operator double() const {
return this->value;
}
};
int main() {
DoubleWrapper a(rand()); //rand to prevent optimization
auto res = std::isfinite(a);
printf("%d", res); //printf to prevent optimization
}
edit 4
So, based on Ben Voigt comment, this is what I added to my class header:
#include <cmath>
namespace std {
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
}
Is this a correct solution ?
The only thing is, should I do the same for all <cmath> functions that takes a double ?
edit 5
I'm responding to Shafik Yaghmour answer here, because a comment is too limited (maybe I should start a new question)
If I understand correctly, instead of my edit 4, I should add this to my class header:
inline bool isfinite(const DoubleWrapper<double> & dw) {
return isfinite((double)dw);
}
using std::isfinite;
Is it required to put it in a namespace, or can I leave it in the "global" namespace ?
But this mean I have to change all my calls from std::isfinite(dw) to isfinite(dw).
Ok, but I realize there are many things I don't understand.
I am confused.
I understand that adding an overload to std is not allowed.
However, adding a template specialization is allowed ? Why ? What difference does it makes ?
Anyway, I tried it, and it is not a solution to my problem because this specialization:
template<> inline __nothrow bool std::isfinite(const MagicTarget<double> & mt) {
return std::isfinite((double)mt);
}
will not be selected by the compiler over the standard one:
template<class _Ty> inline __nothrow bool isfinite(_Ty _X)
{
return (fpclassify(_X) <= 0);
}
To be selected, it should be
template<> inline __nothrow bool std::isfinite(MagicTarget<double> mt) {
return std::isfinite((double)mt);
}
But this would still call the copy Ctor :(
Surprisingly the overload (see edit 4) is selected over the standard template...
I am beginning to think that some C++ rules are too subtle for me :(
But, to begin with, why on earth are cmath functions and especially std::isfinite a template ?
What's the point of accepting anything else that floating points types ?
Anyway, vc++ std::isfinite calls std::fpclassify that is only defined for float, double and long double.
So... What's the point?
I am thinking the standard committee screwed up by allowing cmath functions to be templates. They should only be defined for the types that are relevant, or maybe takes their arguments as universal references.
That's it, sorry for the rant...
I will go for the (not in std) overload.
Thank you!
Addressing edit 4 to your question since through the comments you have come close to a final solution.
You should not be adding it to the std namespace, you should add it to one of your own namespace and rely on argument dependent lookup see Is it a good practice to overload math functions in namespace std in c++ for more details.
Given the standard committee's apparent desire to restrict cmath functions to be called with arithmetic types only, relying on an implicit conversion is not a good idea. So performing an explicit conversion via a cast is the safe way to go for all cmath functions:
isfinite((double)dw)
You can find the details of this in Is it valid to pass non-arithmetic types as arguments to cmath functions?.
I'm working on a legacy library that needs to be backwards compatible with C++03, but is also forward compatible to take advantage of C++11 features like move semantics and explicit casting.
So, is it possible to emulate explicit casting in C++03? I know obviously about the explicit bool (or "safe" bool) idiom - but that's only for casting to a boolean type. Is it possible to emulate a general explicit cast operator in C++03?
I checked around, and found a discussion about this in a book called "Imperfect C++ : Practical Solutions for Real-Life Programming".
In this book, they discuss some ideas about emulating an explicit cast in C++03 (the book was written before C++11). Ultimately, they recommend creating an explicit_cast<T> template. However, I don't like that solution because I want users to simply be able to use static_cast<T>, which works fine in C++11.
So, another solution was to force the compiler to do two conversions, which will disallow implicit conversions. An example of that would be something like:
class int_cast
{
public:
int_cast(const int& v) : m_value(v)
{ }
operator int() const
{
return m_value;
}
private:
int m_value;
};
struct Foo
{
Foo()
{
x = 10;
}
operator int_cast() const
{
return int_cast(x);
}
int x;
};
Here, a Foo should be explicitly convertible to int, but not implicitly. (This code is lifted almost verbatim from Imperfect C++, except in their example they are converting a custom Time object to a std::tm.
However, this doesn't actually work, at least not using GCC 4.7.2:
Foo f;
int x = static_cast<int>(f);
This results in :
test3.cpp: In function ‘int main()’:
test3.cpp:44:28: error: invalid static_cast from type ‘Foo’ to type ‘int’
So I guess "Imperfect C++" is wrong here. The compiler wasn't able to convert a Foo to an int, even with an explicit cast. (Maybe this worked on older compilers?) So, is there anyway to emulate this in C++03 (without using a custom cast operator)?
"Imperfect C++" is right, because it uses a custom "keyword" - actually a function name masquerading as a keyword (not unlike eg.: Tribool's indeterminate). If you try to static_cast you crash against the limitation that the language can only accept conversion chains that involve up to one user-defined type, whereas you have two conversions - from "Foo" to "int_cast" and from there to int.
If you want specifically to be able to static_cast then you'll probably have to hack something with macros to supersede normal static_cast... and accept to live in Undefined Behaviour Land. My preferred choice is to actually work in the inverse direction: simply use explicit_cast and use a macro to redefine it as a static_cast invocation when in C++11 mode. I use explicit cast in my C++ backports toolkit and thus in all the C++ code I write, and I have found no important issues so far.
Consider the following code:
template <typename T>
class B
{
};
template <typename T>
B<T> f(T& t)
{
return B<T>();
}
class A
{
class C {};
C c;
public:
A() {}
decltype(f(c)) get_c() const { return f(c); }
};
int main()
{
A a;
a.get_c();
}
When I try to compile this, I get the error:
test.cpp: In member function 'B<A::C> A::get_c() const':
test.cpp:31:46: error: conversion from 'B<const A::C>' to non-scalar type 'B<A::C>' requested
It seems that in the decltype, the compiler doesn't know that this is a const member function and therefore c is of type const C, and as a result incorrectly deduces the type of f(c) to be B<C> rather than B<const C> which is what it really is.
Am I doing something incorrectly, or is this a compiler bug? I use gcc 4.6, but 4.4 and 4.5 exhibit the same behaviour.
The compiler operates correctly according to the current C++0x WP. See this issue report, which is currently being worked on.
Possibly the final C++0x Standard won't change the meaning of your decltype application in the return type before the function name. You would need to move it to after the parameter list using -> decltype(f(c)), which hopefully will do The Right thing in final C++0x.
No, decltype is not supposed to take into account whether the function is const or not, because it can't. The same could have been written differently:
typedef decltype(f(c)) return_type;
return_type get_c() const { return f(c); }
Correction: decltype(f(c)) shouldn't even compile, because c is not static.
f needs to take an rvalue reference, not an lvalue reference.
I don't think you're allowed to use decltype on anything you wouldn't normally be able to call. I haven't been able to find anything in the standard that would allow you to access c, even within a decltype expression, outside of anywhere you could use c. Since you don't have a this pointer at the point you're trying to do your thing, I don't think you can do what you're trying to do. Doing so doesn't work in MSVC 2010 at least, and it has nothing to do with const.
I considered using declval to get one but you can't access A&&.c because A is an incomplete type at that point. I can't see anyway to do what you're trying to do other than something like so:
decltype(f(declval<C const>())) get_c() const { ... }