defining and calling conversion operator of a class - c++

I'm reading the article at :
http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part-1
and i don't understand some point.
OKAY .How can "Convert" convert itself to any data type?
What does the float() and double() mean at the end of lines below ?? How can converting happen?Could you please explain it with details?
Convert<int>::operator<float> float();
Convert<int>::operator<double> double();
For those of you who wants related part of the article , I'm copy pasting it below and the related part to my question is at the end .
For sure, 'explicit template argument specification' with method template is also possible. Consider another example:
template<class T>
class Convert
{
T data;
public:
Convert(const T& tData = T()) : data(tData)
{ }
template<class C>
bool IsEqualTo( const C& other ) const
{
return data == other;
}
};
Which can be utilized as:
Convert<int> Data;
float Data2 = 1 ;
bool b = Data.IsEqualTo(Data2);
It instantiates Convert::IsEqualTo with float parameter. Explicit specification, as given below, would instantiate it with double:
bool b = Data.IsEqualTo<double>(Data2);
One of the astounding thing, with the help of templates, you can do it by defining conversion operator on top of template!
template<class T>
operator T() const
{
return data;
}
It would make possible to convert the Convert' class template instance into any type, whenever possible. Consider following usage example:
Convert<int> IntData(40);
float FloatData;
double DoubleData;
FloatData = IntData;
DoubleData = IntData;
Which would instantiate following two methods (fully qualified names):
Convert<int>::operator<float> float();
Convert<int>::operator<double> double();
On one hand it provides good flexibility, since without writing extra code, Convert can convert itself (the specific instantiation) to any data-type - whenever conversion is possible at compilation level. If conversion is not possible, like from double to string-type, it would raise an error.

A class type can have user-defined conversions. This allows you to convert an instance of the class into another type. For example, here we have a struct that when converted to an int always has the value 42:
struct A {
operator int() { return 42; }
};
This is a special function, operator int, that is called for conversion to an int. Now if we have an instance of A, a, we can easily convert it to an int:
A a;
int x = a; // x now has the value 42
In the article, they are showing how you can use templates to generate a conversion operator for any type. The function template is defined as:
template<class T>
operator T() const
{
return data;
}
Now, for whenever you try to convert your object into another type, a new version of that function will be generated, replacing T with the type that you're converting to. So if we do float f = a, the following function will generated:
operator float() const
{
return data;
}
This is a function that returns the internal data as a float.
The two lines in the article that are confusing you are just showing you which functions would be generated by the example:
Convert<int>::operator<float> float();
Convert<int>::operator<double> double();
The first is operator float that converts to a float. The second is operator double that converts to a double.

Related

argument of type * is incompatible with parameter of type "const float *"

I'm fairly new to C++. I've searched extensively but I couldn't make it work.
I've defined a custom type called vec_t:
class FloatType {
private:
float value;
public:
FloatType() : value(0.0f) {}
FloatType(float v) : value(v) {}
//operator float() { return value; }
//operator float() { return value; }
//explicit operator const float* () { return &value; }
//operator float* () const { return &value; }
//operator const float* () { return &value; }
//operator const float() { return (const float)value; }
//operator const float*() { return &value; }
};
typedef FloatType vec_t;
I've also created a function which takes a const float * as its only argument:
void Create(const float* vColor = NULL);
void Create(const float* vColor) {
//...
}
Now, when calling the function like so:
vec_t a = { 2.5f };
vec_t* b = &a;
Create(b);
Visual Studio Community 2019 (v142) is complaining:
argument of type "vec_t *" is incompatible with parameter of type "const float *"
Now, casting it to const float * on the spot gets it done:
Create((const float *)b);
But, my goal is to have an implicit casting operator to implicitly convert from my type to const float *, but no matter my efforts, I can not seem to have it right.
All operator comments were my attempts and they all have valid syntax, but they don't make the problem go away.
What am I not understanding?
I want to be able to handle this from within the FloatType class itself, and to my knowledge, an implicit casting operator is the way to do so.
Don't guide me to another approach, this is purely for practice and exercise.
The problem is that while vec_t is a class type that can have conversion operators defined, vec_t * is a primitive type (a pointer), and no user-defined conversions apply to it.
Some possible solutions:
Don't pass around pointers to vec_t, pass them by value instead. If necessary, use std::move to avoid potentially expensive copies. This boils down to just Create(a). john's answer explains this in more detail.
Dereference the pointer, as in Create(*b), to allow the compiler to find your user-defined conversions.
Add a float * data() member function to vec_t, just like std::vector, and call that to get at the underlying data: Create(b->data())
Don't use your own vector type and just use std::array<float, N> for statically-sized vectors and std::vector<float> for dynamically sized ones. This is likely the best solution. To get a pointer to the raw data, use vec.data(). (Again, take advantage of these types' value semantics to get memory safety. Move / copy them, don't use raw pointers.)
If you want something really ugly that you shouldn't do: Create(b->operator float *()).
Your vec_t type is not a pointer, so you should not be using a pointer as the argument when calling Create():
class FloatType
{
private:
float value;
public:
...
operator const float* () const { return &value; }
// const here ^^^^^
};
typedef FloatType vec_t;
vec_t a = { 2.5f };
Create(a);
For some reason, you introduced the pointer b, that's the main reason your code doesn't work.
Also, you should have an extra const on your conversion operator, as I've indicated above.

Can I replicate inheritance with overloading?

Prelude: I have updated this question to address NicolBolas' suggestion. Please leave a constructive comment if you downvote, thank you.
I'm writing a function that takes a number (uint) or a flag that it's not a number. It then goes on to work with the given number or -1.
Here's the idea
struct Numeric {
virtual int to_int() const = 0;
};
struct NotANumber : Numeric {
int to_int () const {
return -1;
}
}
struct Number : Numeric {
const uint n;
Number (const uint n): n(n) {}
int to_int () const {
return n;
}
};
So then my function could be used as:
calculate_stuff(NotANumber());
calculate_stuff(Number(4));
My question is whether it's possible to move the to_int method outside of the classes, into the form of an overloaded function:
struct Numeric {};
struct NotANumber : Numeric {}
struct Number : Numeric {
const uint n;
Number (const uint n): n(n) {}
};
int Numeric_to_int (const NotANumber) {
return -1;
}
int Numeric_to_int (const Number n) {
return n.n;
}
This doesn't seem to work. Is it possible to fix this? Is the issue that overloading happens at compile time, whereas overriding is at runtime?
(I think I'm going to use std::optional and value_or for this specific problem, but I would still like to know the answer to my questions above)
Edit: sorry, I should've clarified what "doesn't work" means:
int calculate_stuff (const Numeric n) {
std::cout << Numeric_to_int(n) << std::endl;
return 0;
}
This doesn't compile: no matching function for call to ‘Numeric_to_int(const Numeric&)’
int calculate_stuff (const Numeric n)
How could it work? You passed in a base class. By value. The compiler cannot know what derived class it used to be. In fact, since you took the base class by value, the compiler knows that n is neither of the derived classes.
C++ isn't Java; if you pass something by value, you make a copy (or move to it). And if you passed one of the derived classes, that causes slicing; you only copy the base class data. The parameter is therefore exactly what it says: an object who's dynamic type is Numeric. Exactly and only that, not one of its derived classes.
Even if you took a const Numeric &n instead, that won't help. The compiler doesn't know what type it used to be. And you can't even use dynamic_cast to convert it back, since Numeric is not a polymorphic class.
A better way to handle this is to actually use a proper variant class (optional is effectively a specialized variant).
My question is whether it's possible to move the to_int method outside of the classes, into the form of an overloaded function.
Using overloaded non-member functions is a viable option only if you deal with the derived types at all times.
If you need the functionality through a reference or pointer to the base class type, then using overloaded non-member functions is not a viable option. In that case, a virtual member function is the right choice.
You can use a template class and an using declaration to do that:
template<int v>
struct Numeric {};
using NotANumber = Numeric<-1>;
template<int N>
constexpr int Numeric_to_int (Numeric<N>) {
return N;
}
int main() {
static_assert(Numeric_to_int(NotANumber{}) == -1, "!");
static_assert(Numeric_to_int(Numeric<42>{}) == 42, "!");
}
Also, consider the use of a std::integral_constant for the same purpose.
As an example:
template<int v>
using Numeric = std::integral_constant<int, v>;

Integer c++ wrapper

I'm doing a very small and simple Integer class wrapper in C++, which globaly looks like this:
class Int
{
...
private:
int value;
...
}
I handled almost all the possible assignements, but I don't find out what kind of operator I have to use to get native left assignement.
eg:
Int myInteger(45);
int x = myInteger;
You might want a conversion operator to convert to int:
class Int
{
public:
operator int() const { return value; }
...
};
This allows the following initialization of an int
int x = myInteger;
In C++11, you can decide whether you restrict that conversion to int, or whether you allow further conversions from int to something else. To restrict to int, use an explicit conversion operator:
explicit operator int() const { return value; }
although it is probably not necessary in this case.

Overwrite Cast Operator in C++

As a C++ beginner I want to write some simple type casts. It there a way to create casting logic which can be used in the type new = (type)old format with the prefix parentheses?
string Text = "Hello";
char* Chars = "Goodbye";
int Integer = 42;
string Message = Text + (string)Integer + (string)Chars + "!";
I'd like to stick with this syntax if possible. For example the string cast of boost int Number = boost::lexical_cast<int>("Hello World") has an unattractive long syntax.
Just use a normal function that you overload for different types:
std::string str(int i) {
return "an integer";
}
std::string str(char* s) {
return std::string(s);
}
Then use if not like a cast, but as a normal function call:
string Message = Text + str(Integer) + str(Chars) + "!";
It's the most common thing in C++ to cast using a NAME<TYPE>(ARGUMENT) syntax, like in static_cast<int>(char). It makes sense to extend this the way boost does.
However, if you want to convert non-primitive types, you can use non-explicit constructors with a single argument and the cast operator.
class MyType {
public:
MyType(int); // cast from int
operator int() const; // cast to int
};
This is not possible if you are dealing with already existing types.
You cannot change the behaviour of the C-style cast. C++ will make up its mind how to interpret such a cast.
You could however come up with an intermediate type that shortens the syntax:
template <typename From>
struct Cast {
From from;
Cast(From const& from) : from(from) {}
template <typename To>
operator To() const {
return convert(from,To());
}
};
template <typename From>
Cast<From> cast(From const& from) {
return Cast<From>(from);
};
std::string convert(int, std::string const&);
This would allow you to convert things explicitly but without stating how exactly:
int i = 7;
std::string s = cast(i);

C++: Casting for user defined types

How can I get the same handeling of casting for user-defined types as built in, eg:
float a = 5.4;
std::string s = a;//error, no conversion avaible
int x = a;//warning, possible data loss
int y = (int)a;//fine
int z = static_cast<int>a;//fine
float b = c;//warning, possible data loss
Now say I have my own Int and Float class, how do I go about getting the same errors and warnings?
class Int
{
public:
int value;
Int(int v);
...
};
class Float
{
public:
float value;
Float(float v);
...
};
Int c = 10;
Float a = 5.5;
std::string s = a;
Int x = a;
Int y = (Int)a;
Int z = static_cast<Int>a;
Float b = c;
I'm aware of creating overloaded cast operators, and using constructors, however I don't know how to make this work correctly for implicit and explicit casts, eg consider. If I dont add explicit casts within those methods, then I get a warning when there compiled but not when their call, and if I do, then I don't get an error within the classes code, but I still don't get a warning when there used either.
I'm guessing there is some way as to mark the cast operator as explicit, so that a warning is generated if it tries to cast implicitly, but not with explicit (either C-Style or static_cast) casts)
EDIT:
Ok I think I get it for cases like this where all types in question are fully, known, but what about times when one or both are templates, and that neither types map onto a built-in type?
template<typename T> class Vector2
{
public:
T x, y;
Vector2():x(0),y(0){}
Vector2(T x, T y):x(x),y(y){}
//Works as expected, warning if adding T and T2 is unsafe, or error if
//incompatible*/
template<typename T2>Vector2<T>& operator += (const Vector2<T2> &v);
//Also works as desired
Vector2<T>& operator *= (T s);
//allows the conversion, but always generates warnings if
//T and T2 would, even if this constructor is used by an explicit
//case. How can I suppress the warnings for the explicit cast, but
//not for implicit casts?
template<typename T2>Vector2(const Vector2<T2> &v);//uses implicit conversion form T2 to T
};
An implicit cast from say Vector2 to Vector2 works as expected, but the cast from say Vector2 to Vector2 always causes (2, one for x and one for y) warnings, even if a explicit C-Style or static_cast was used. I want to keep the warnings for the implicit cast, but not the explicit casts.
I know I could hack around this be creating a special T vector_cast(T2) type method that uses explicit casts for each element internally, but Id rather be able to use the C-Style and static_casts
I don't think there's a way, either. The best I could achieve is so that the line that you want to generate a warning doesn't compile at all.
class Int
{
public:
int value;
Int(int v);
};
class Float
{
public:
float value;
Float(float v);
operator int() { return static_cast<int>(value); }
};
int main()
{
Float a = 5.5;
//Int x = a; //no warning, simply doesn't compile
Int y = (int)a;
Int z = static_cast<int>(a);
}
Edit: regarding your question about Vector2
One thing to do might be to disable all implicit conversions between different Vector2 types. As a short-cut you might provide a vector_cast to allow explicit conversions:
template <class T, class S>
Vector2<T> vector_cast(const Vector2<S>& s)
{
return Vector2<T>(static_cast<T>(s.x), static_cast<T>(s.y));
}
Another thing might be to bring in some template metaprogramming, to enable conversion constructor for safe conversions.
It seems to me that boost doesn't contain such a type_trait, hence I rolled my own.
It is somewhat simplified: Target must be at least as large as Source, and Target must not be integral if Source is floating point. However, it disregards issues of signedness, and the question whether a floating-point type can represent the full range of an integer type (e.g float cannot store all 32-bit ints precisely, but double can).
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
template <class S, class T>
struct is_safe_conversion:
boost::integral_constant<
bool,
(sizeof(S) <= sizeof(T)) && !(boost::is_floating_point<S>::value && boost::is_integral<T>::value)
>
{
};
template<typename T> class Vector2
{
public:
T x, y;
Vector2():x(0),y(0){}
Vector2(T x, T y):x(x),y(y){}
template <class U>
Vector2(const Vector2<U>& other, typename boost::enable_if<is_safe_conversion<U, T> >::type* = 0):
x(other.x), y(other.y) {}
};
template <class T, class S>
Vector2<T> vector_cast(const Vector2<S>& s)
{
return Vector2<T>(static_cast<T>(s.x), static_cast<T>(s.y));
}
int main()
{
Vector2<double> vd, vd2;
Vector2<int> vi, vi2;
Vector2<float> vf, vf2;
vd = vd2;
vd = vi;
vd = vf;
//vi = vd; //error
vi = vector_cast<int>(vd);
vi = vi2;
//vi = vf; //error
vi = vector_cast<int>(vf); //explicit
//vf = vd; //error
vf = vector_cast<float>(vd);
//following compiles, but produces a warning (float cannot represent all integers)
//TODO: enhance is_safe_conversion!
vf = vi;
vf = vf2;
}
Some of what you want won't be possible, because it relies on special knowledge the compiler has about the types involved, and you can't teach the compiler these things.
The items you showed should do the following:
Float a = 5.5;
Should work without complaint.
std::string s = a;
Should give some compiler error, not necessarily the same as using a POD float, but still it will refuse, since your Float doesn't have a const char* operator. (And if it does, remove it to cause this error.)
Int x = a;
You should still get a warning about possible data loss here, unless Float has an "operator int()". If so, remove it, so the compiler is forced to use "operator float()", causing the warning.
Int y = (int)a;
Should work without complaint.
Int z = static_cast<int>a;
This should have the same apparent effect as the previous one. (There are technical differences between them, but in this case, they shouldn't matter.)
Float b = c;
You don't show what 'c' is, so I can't say what this will do.
I don't think there's any way to create your own compiler warning for your cast.