Templated function can't convert 'int' to nullptr_t - c++

TL;DR:
Why can't templated functions access the same conversions that non-templated functions can?
struct A {
A(std::nullptr_t) {}
};
template <typename T>
A makeA(T&& arg) {
return A(std::forward<T>(arg));
}
void foo() {
A a1(nullptr); //This works, of course
A a2(0); //This works
A a3 = makeA(0); //This does not
}
Background
I'm trying to write some templated wrapper classes to use around existing types, with the goal of being drop-in replacements with minimal need to rewrite existing code that uses the now-wrapped values.
One particular case I can't get my head around is as follows: we have a class which can be constructed from std::nullptr_t (here called A), and as such, there's plenty of places in the code base where someone has assigned zero to an instance.
However, the wrapper cannot be assigned a zero, despite forwarding the constructors. I have made a very similar example that reproduces the issue without using an actual wrapper class - a simple templated function is sufficient to show the issue.
I would like to allow that syntax of being able to assign zero to continue to be allowed - it isn't my favourite, but minimising friction to moving to newer code is often a necessity just to get people on board with using them.
I also don't want to add a constructor that takes any int other than zero because that's very much absurd, was never allowed before, and it should continue to be caught at compile time.
If such a thing is not possible, it would satisfy me to find an explanation, because with as much as I know so far, it makes no sense to me.
This example has the same behaviour in VC++ (Intellisense seems to be OK with it though...), Clang, and GCC. Ideally a solution will also work in all 3 (4 with intellisense) compilers.
A more directly applicable example is follows:
struct A {
A(){}
A(std::nullptr_t) {}
};
template <typename T>
struct Wrapper {
A a;
Wrapper(const A& a):a (a) {}
template <typename T>
Wrapper(T&& t): a(std::forward<T>(t)){}
Wrapper(){}
};
void foo2() {
A a1;
a1 = 0; // This works
Wrapper<A> a2;
a2 = 0; //This does not
}

Why has the compiler decided to treat the zero as an int?
Because it is an integer.
The literal 0 is a literal. Literals get to do funny things. String literals can be converted into const char* or const char[N], where N is the length of the string + NUL terminator. The literal 0 gets to do funny things too; it can be used to initialize a pointer with a NULL pointer constant. And it can be used to initialize an object of type nullptr_t. And of course, it can be used to create an integer.
But once it gets passed as a parameter, it can't be a magical compiler construct anymore. It becomes an actual C++ object with a concrete type. And when it comes to template argument deduction, it gets the most obvious type: int.
Once it becomes an int, it stops being a literal 0 and behaves exactly like any other int. Not unless it is used in a constexpr context (like your int(0)), where the compiler can figure out that it is indeed a literal 0 and therefore can take on its magical properties. Function parameters are never constexpr, and thus they cannot partake in this.

See [conv.ptr]/1:
A null pointer constant is an integer literal with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type [...]
So the integer literal 0 can be converted to a null pointer. But if you attempt to convert some other integer value, that is not a literal, to a pointer type then the above quote does not apply. In fact there is no other implicit conversion from integer to pointer (since none such is listed in [conv.ptr]), so your code fails.
Note: Explicit conversion is covered by [expr.reinterpret.cast]/5.

Related

Is it possible in C++ to enforce a string-literal function argument?

I'm wondering if it's possible in C++ to declare a function parameter that must be a string literal? My goal is to receive an object that I can keep only the pointer to and know it won't be free()ed out from under me (i.e. has application lifetime scope).
For example, say I have something like:
#include <string.h>
struct Example {
Example(const char *s) : string(s) { }
const char *string;
};
void f() {
char *freeableFoo = strdup("foo");
Example e(freeableFoo); // e.string's lifetime is unknown
Example e1("literalFoo"); // e1.string is always valid
free(freeableFoo);
// e.string is now invalid
}
As shown in the example, when freeableFoo is free()ed the e.string member becomes invalid. This happens without Example's awareness.
Obviously we can get around this if Example copies the string in its constructor, but I'd like to not allocate memory for a copy.
Is a declaration possible for Example's constructor that says "you must pass a string literal" (enforced at compile-time) so Example knows it doesn't have to copy the string and it knows its string pointer will be valid for the application's lifetime?
In C++20 you can do it using a wrapper class that has a consteval converting constructor which takes a string literal:
struct literal_wrapper
{
template<class T, std::size_t N, std::enable_if_t<std::is_same_v<T, const char>>...>
consteval literal_wrapper(T (&s)[N]) : p(s) {}
char const* p;
};
The idea is that string literals have type const char[N] and we match this.
Then you can use this wrapper class in places where want to enforce passing a string literal:
void takes_literal(string_literal lit) {
// use lit.p here
}
You can call this as foo("foobar").
Note that this will also match static-storage const char[] arrays, like so:
const char array[] = {'a'};
takes_literal(array); // this compiles
Static arrays have most of the same characteristics as string literals, however, e.g., indefinite storage duration, which may work for you.
It does not match local arrays because the decayed pointer value is not a constant expression (that's where consteval comes in).
This answer is almost directly copied from the first variant suggested in C.M.'s comment on the question.
if it's possible in C++ to declare a function parameter that must be a string literal?
In C++ string literals have type char const[N], so that you can declare a parameter to be of such a type:
struct Example {
template<size_t N>
Example(char const(&string_literal)[N]); // In C++20 declare this constructor consteval.
template<size_t N>
Example(char(&)[N]) = delete; // Reject non-const char[N] arguments.
};
However, not every char const[N] is a string literal. One can have local variables and data members of such types. In C++20 you can declare the constructor as consteval to make it reject non-literal arguments for string_literal parameter.
Conceptually, you'd like to determine the storage duration of the argument to a constructor/function parameter. Or, more precisely, whether the argument has a longer lifetime than Example::string reference to it. C++ doesn't provide that, C++20 consteval is still a poor-man's proxy for that.
gcc extension __builtin_constant_p detetmines whether an expression is a compile-time constant which is widely used in preprocessor macros in Linux kernel source code. However, it can only evaluate to 1 on expressions, but never on functions' parameters, so that its use is limited to preprocessor macros.
The traditional solution for the problem of different object lifetimes has been organizing objects into a hierarchy, where objects at lower levels have smaller lifetimes than objects at higher levels, and hence, an object can always have a plain pointer to an object at a higher level of hierarchy valid. This approach is somewhat advanced, labour intensive and error prone, but it totally obviates the need for any garbage collection or smart-pointers, so that it's only used in ultra critical applications where no cost is too high. The opposite extreme of this approach is using std::shared_ptr/std::weak_ptr for everything which snowballs into maintenance nightmare pretty rapidly.
Just make the constructor explicitly taking rvalue:
struct Example {
Example(const char*&& s) : string(s) { }
const char* string;
};

How can a POD type add support for reinterpret_cast'ing it?

I'm trying to replace a type, typedef'ed from a built-in integral type, used in a large project with a custom class, which would implement some additional functionality like avoiding truncation on assignment etc. But the project extensively uses a conversion like reinterpret_cast<void*>(value). I've done a naive attempt at implementing an operator void*() in my new class, but apparently this doesn't make it possible to reinterpret_cast, only allows to static_cast to void*. Here's the code:
#include <cstdlib>
#include <type_traits>
#define USE_NEW_VALUE_TYPE
#ifdef USE_NEW_VALUE_TYPE
struct Value
{
size_t value;
operator void* () { return reinterpret_cast<void*>(value); }
};
static_assert(std::is_pod<Value>::value,"Value is not POD");
#else
typedef size_t Value;
#endif
int main()
{
Value v{5};
void* p=reinterpret_cast<void*>(v); // This is how the project uses it
}
I thought that if the class is POD, this would allow me to do such things like a reinterpret_cast. But this code gives me a compilation error:
invalid cast from type ‘Value’ to type ‘void*’
So my question is then: how do I add support for such a reinterpret_cast, so that I didn't have to manually switch it to static_cast in every part of the project?
Unfortunately, reinterpret_cast is not designed for this. The reason this works for POD types is #3 on the cppreference website:
A value of any integral or enumeration type can be converted to a pointer type. A pointer converted to an integer of sufficient size and back to the same pointer type is guaranteed to have its original value, otherwise the resulting pointer cannot be dereferenced safely (the round-trip conversion in the opposite direction is not guaranteed; the same pointer may have multiple integer representations) The null pointer constant NULL or integer zero is not guaranteed to yield the null pointer value of the target type; static_cast or implicit conversion should be used for this purpose.
And, I believe §12.3.2 plays a role here:
A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.
In short: User-defined conversions do not participate in resolution of reinterpret_casts.
Possible solutions
1. Explicitly take the address of v:
void* p=reinterpret_cast<void*>(&v);
2. Defined operator void*() as you did, you could write
void *p = v;
Note: This probably opens up a wormhole of problems due to unwanted implicit conversions
3. Use static_cast as you said yourself.
Note: use &v rather than defining operator void*() for the same reason as in No. 2
4. Ideally, but probably unrealistic, fix the underlying design issue requiring casting classes to void
No. 3 might be the least painful solution here.
EDIT for comment
There are two ways here:
1. Use an overloaded address-of operator (operator&). This may not be possible depending on how Value is used.
#include <cstdlib>
struct Value
{
size_t value;
void* operator &() { return reinterpret_cast<void*>(value); }
};
int main()
{
Value v;
void* p=reinterpret_cast<void*>(&v); // This is how the project uses it
}
2. Implement an operator uintptr_t. While this requires verbose double-casting, it transfers the conversion into the Value class, and uintptr_t is guaranteed to be able to hold a void*.
#include <cstdlib>
struct Value
{
size_t value;
operator uintptr_t() { return static_cast<uintptr_t>(value); }
};
int main()
{
Value v;
void* p=reinterpret_cast<void*>(static_cast<uintptr_t>(v)); // This is how the project uses it
// or less verbose
void* p2=reinterpret_cast<void*>(uintptr_t(v));
}
C++ language doesn't allow overrides for reinterpret_cast. See Overloading c++ typecasting (functions)
1) Replace all such casts with helper functions like:
template <class T>
void* integer_to_voidptr(T t)
{
return reinterpret_cast<void*>(t);
}
template <class T>
T voidptr_to_integer(void* p)
{
return reinterpret_cast<T>(p);
}
2) Add non-template overloads or specialize the templates for your POD.
You can change the call sites to a form that works with both casts:
void* p = reinterpret_cast<void*&>(v);
add this character ^
This effectively treats 'v' as an object that holds a void*, which is true in both cases. The automatic lvalue-to-rvalue conversion will insert a de-reference, extracting either the original size_t or the embedded size_t in Value.
This code is equivalent to:
void* p = *reinterpret_cast<void**>(&v);
However there is no way to get reinterpret_cast to call a custom operator on your object; the point of reinterpret_cast is that it's completely invisible.

Is there a way to use only the object name of a class as a "default" member?

Think in a similar fashion like:
1. The bare name of an array is equivalent with the pointer to the first element, without the need to specify index 0.
2. toString() from Java makes it possible to use the name of an object as a string without calling any object method.
Now is there a way in C++ to use the name of a class object to refer to its first member?
Consider:
class Program
{
public:
int id;
char *str;
};
void function(int p)
{
//...
}
and then:
Program prog0;
function(prog0); // instead of function(prog0.id)
Any way to "hide" the member reference?
EDIT:
Why was the holyBlackCat's answer deleted? I was inclining to vote it as the best answer -- no offense, Mateusz. But he was the first to suggest conversion operator and the example was complete and simple.
In C++, such behaviour would be a cataclysm. If I understand correctly, Java tries to convert object of type A to object of type B by searching for first member in A, that is of type B or is implicitly convertible to B.
C++ wasn't designed that way. We like to write code, that is always predictable. You can achieve what you want, but for a price.
The best solution in this case would be conversion operator - consider:
class Program
{
public:
int id;
char *str;
operator int()
{
return this->id;
}
//You can have more than one!
operator const char*()
{
return this->str;
}
};
void function_int(int p)
{
}
void function_str(const char* s)
{
}
Now it is possible to do the following:
Program prog;
function_int(prog); //Equivalent of function_int(prog.id)
function_str(prog); //Equivalent of function_int(prog.str)
The price is, that if you add another int and place it before id it will not be used in conversion, because we stated in our operator explicitly, that "int content" of our class is represented by id and this member is considered when it comes to such conversion.
However, even this simple example shows some potential problems - overloading functions with integral and pointer types could result in very unpredictable behavior. When type contains conversion operators to both pointers and integers, it can get even worse.
Assume, that we have following function:
void func(unsigned long)
{
}
And we call func with argument of type Program. Which conversion operator would you expect to be called? Compiler knows how to convert Program to either int or const char*, but not unsigned long. This article on cppreference should help you to understand how implicit conversions work.
Also, as Barry pointed out, more meaningless constructs become available. Consider this one:
int x = prog + 2
What does it mean? It is perfectly valid code, though. That is why conversion operators should be dosed extremely carefully (in pre-C++11 era, there was a general advise, that every class should have at most one such operator).
Quote from MSDN:
If a conversion is required that causes an ambiguity, an error is generated. Ambiguities arise when more than one user-defined conversion is available or when a user-defined conversion and a built-in conversion exist.
Sometimes, simple solution to this problem is to mark conversion operator with explicit keyword, so you would need to change above calls to:
function_int((int)prog);
function_str((const char*)prog);
It is not as pretty as the previous form, but much safer. It basically means, that compiler is forbidden to perform any implicit conversion using operator marked as explicit. Very useful to avoid ambiguous calls, while still providing some flexibility in code - you can still very easily convert objects of one type to another, but you can be sure when and where these conversions are performed.
However, explicit conversion operators are still not supported by some compilers, as this is C++ 11 feature (for example, Visual C++ 11 doesn't support it).
You can read more about explicit keyword here.
Now is there a way in C++ to use the name of a class object to refer to its first member?
No, C++ doesn't have any reflection, so there's no way to actually determine what the "first member" is.
However, if what you really want is to get an ID for any object, you could just require that object to have that method:
template <typename T>
void function(const T& t) {
int id = t.getID();
// etc.
}
Without knowing more about your use-case, it's hard to know what to propose.

Let the compiler make the final choice which type to use

This question requires knowledge of C++ template meta-programming as (indirectly) expression templates are involved. I say indirectly because its not directly a question on expression templates, but involves C++ type computations. If you don't know what that is please don't answer this question.
To avoid putting out a question without enough background information let me elaborate a bit on the general problem I am trying to solve and then go to the more specific parts.
Suppose you have a library that provides Integers that the user can do calculations with just like with ints.
Furthermore it is possible to construct a Integer from an int. Just like:
Integer<int> i(2);
Internally my Integer class is a class template:
template<class T>
class Integer {
// cut out
};
So I can define it on whatever integer type I like.
Now without changing the API, I would like to change the library in a way that if Integer was constructed from an int it should be represented internally by a different type, say IntegerLit. The reason for this is that I can speed up some calculation knowing that an instance of Integer was created from an int (can pass it as a int argument to a function instead of as a general object described by a base pointer + separate data. This just as a comment.)
It is essential that the type is different when constructing from an int because I need the compiler to take up different code paths depending on whether constructed from an int or not. I cannot do this with a runtime data flag. (The reason in short: The compiler generates a function that takes either an int or the above mentioned more general type of object depending on the type.)
Having this said I run into a problem: When the uses does something like this:
Integer<int> a,b(2);
a = b + b;
Here a should be the general Integer and b the specialized IntegerLit. However, my problem is how to express this in C++ as the user is free to use the very same type Integer to define her variables.
Making the types polymorphic, i.e. deriving IntegerLit from Integer won't work. It looks fine for a moment. However since the user creates instances of Integer (the base class) that won't work because it is the base class the compiler sticks into the expression tree (this is why expression templates are involved in the question). So again no distinction is possible between the two cases. Doing a RTTI check a la dynamic cast is really not what I want on that point.
More promising seems to be adding a literal template parameter bool lit to the type saying if it was constructed from an int or not. The point is to not specify the conversion rule for one not literal one but do specify it for the other case.
However, I can't get that to work. The following code only compiles (GCC 4.7 C++11) if not constructing from an int. Otherwise it fails because the Integer is not specified with true as the value for lit. So the compiler searches the default implementation which doesn't have the conversion rule. It is not an option changing the API and requiring to write Integer<int,true> when constructing from an int.
template<class T,bool lit=false>
class Integer
{
public:
Integer() {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
T F;
};
template<>
template<class T>
class Integer<T,true>
{
public:
Integer(int i) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
T F;
};
I am starting wondering if something like this is possible with C++.
Is there maybe a new feature of C++11 that can help here?
No, this isn't how C++ works. If you define b as Integer b, then it's an Integer. THis applies regardless of the expression which is subsequently used to initialize b.
Also, consider the following: extern Integer b;. There's an expression somewhere else that initializes b, yet the compiler still has to figure out here what type b has. (Not "will have", but "has").
You can't do that, exactly anyways.
But using "auto" you can come close.
// The default case
Integer<int> MakeInt()
{
return Integer<int>();
}
// The generic case
template <class T>
Integer<T> MakeInt(T n)
{
return Integer<T>(n);
}
// And specific to "int"
Integer<IntegerLit> MakeInt(int n)
{
return Integer<IntegerLit>(n);
}
auto a = MakeInt();
auto b = MakeInt(2);
auto c = MakeInt('c');
auto d = MakeInt(2.5);
You can't do that. Once you've said a variable is Integer<int> that is the variable's type. What you can do is make the underlying rep of the Integer vary depending on which constructor is used, something like this:
template<class T>
class Integer {
// cut out
Integer() : rep_(IntRep()) {}
explicit Integer(int val) : rep_(IntLitRep(val)) {}
private:
boost::variant<IntRep, IntLitRep> rep_;
};
Then you can easily determine which variant version is active and utilize different code paths when needed.
EDIT: In this case even though the type of the Integer is the same, you can easily use template functions to make it appear that it's behaving as two separate types (since the rep changes effective type).

why implicit conversion is harmful in C++

I understand that the keyword explicit can be used to prevent implicit conversion.
For example
Foo {
public:
explicit Foo(int i) {}
}
My question is, under what condition, implicit conversion should be prohibited? Why implicit conversion is harmful?
Use explicit when you would prefer a compiling error.
explicit is only applicable when there is one parameter in your constructor (or many where the first is the only one without a default value).
You would want to use the explicit keyword anytime that the programmer may construct an object by mistake, thinking it may do something it is not actually doing.
Here's an example:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
With the following code you are allowed to do this:
int age = 29;
//...
//Lots of code
//...
//Pretend at this point the programmer forgot the type of x and thought string
str s = x;
But the caller probably meant to store "3" inside the MyString variable and not 3. It is better to get a compiling error so the user can call itoa or some other conversion function on the x variable first.
The new code that will produce a compiling error for the above code:
class MyString
{
public:
explicit MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
Compiling errors are always better than bugs because they are immediately visible for you to correct.
It introduces unexpected temporaries:
struct Bar
{
Bar(); // default constructor
Bar( int ); // value constructor with implicit conversion
};
void func( const Bar& );
Bar b;
b = 1; // expands to b.operator=( Bar( 1 ));
func( 10 ); // expands to func( Bar( 10 ));
A real world example:
class VersionNumber
{
public:
VersionNumber(int major, int minor, int patch = 0, char letter = '\0') : mMajor(major), mMinor(minor), mPatch(patch), mLetter(letter) {}
explicit VersionNumber(uint32 encoded_version) { memcpy(&mLetter, &encoded_version, 4); }
uint32 Encode() const { int ret; memcpy(&ret, &mLetter, 4); return ret; }
protected:
char mLetter;
uint8 mPatch;
uint8 mMinor;
uint8 mMajor;
};
VersionNumber v = 10; would almost certainly be an error, so the explicit keyword requires the programmer to type VersionNumber v(10); and - if he or she is using a decent IDE - they will notice through the IntelliSense popup that it wants an encoded_version.
Mostly implicit conversion is a problem when it allows code to compile (and probably do something strange) in a situation where you did something you didn't intend, and would rather the code didn't compile, but instead some conversion allows the code to compile and do something strange.
For example, iostreams have a conversion to void *. If you're bit tired and type in something like: std::cout << std::cout; it will actually compile -- and produce some worthless result -- typically something like an 8 or 16 digit hexadecimal number (8 digits on a 32-bit system, 16 digits on a 64-bit system).
At the same time, I feel obliged to point out that a lot of people seem to have gotten an almost reflexive aversion to implicit conversions of any kind. There are classes for which implicit conversions make sense. A proxy class, for example, allows conversion to one other specific type. Conversion to that type is never unexpected for a proxy, because it's just a proxy -- i.e. it's something you can (and should) think of as completely equivalent to the type for which it's a proxy -- except of course that to do any good, it has to implement some special behavior for some sort of specific situation.
For example, years ago I wrote a bounded<T> class that represents an (integer) type that always remains within a specified range. Other that refusing to be assigned a value outside the specified range, it acts exactly like the underlying intger type. It does that (largely) by providing an implicit conversion to int. Just about anything you do with it, it'll act like an int. Essentially the only exception is when you assign a value to it -- then it'll throw an exception if the value is out of range.
It's not harmful for the experienced. May be harmful for beginner or a fresher debugging other's code.
"Harmful" is a strong statement. "Not something to be used without thought" is a good one. Much of C++ is that way (though some could argue some parts of C++ are harmful...)
Anyway, the worst part of implicit conversion is that not only can it happen when you don't expect it, but unless I'm mistaken, it can chain... as long as an implicit conversion path exists between type Foo and type Bar, the compiler will find it, and convert along that path - which may have many side effects that you didn't expect.
If the only thing it gains you is not having to type a few characters, it's just not worth it. Being explicit means you know what is actually happening and won't get bit.
To expand Brian's answer, consider you have this:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
// ...
};
This actually allows this code to compile:
MyString mystr;
// ...
if (mystr == 5)
// ... do something
The compiler doesn't have an operator== to compare MyString to an int, but it knows how to make a MyString out of an int, so it looks at the if statement like this:
if (mystr == MyString(5))
That's very misleading since it looks like it's comparing the string to a number. In fact this type of comparison is probably never useful, assuming the MyString(int) constructor creates an empty string. If you mark the constructor as explicit, this type of conversion is disabled. So be careful with implicit conversions - be aware of all the types of statements that it will allow.
I use explicit as my default choice for converting (single parameter or equivalent) constructors. I'd rather have the compiler tell me immediately when I'm converting between one class and another and make the decision at that point if the conversion is appropriate or instead change my design or implementation to remove the need for the conversion completely.
Harmful is a slightly strong word for implicit conversions. It's harmful not so much for the initial implementation, but for maintenance of applications. Implicit conversions allow the compiler to silently change types, especially in parameters to yet another function call - for example automatically converting an int into some other object type. If you accidentally pass an int into that parameter the compiler will "helpfully" silently create the temporary for you, leaving you perplexed when things don't work right. Sure we can all say "oh, I'll never make that mistake", but it only takes one time debugging for hours before one starts thinking maybe having the compiler tell you about those conversions is a good idea.