In this code:
template<class T>
struct Side
{
};
template<class T>
struct LeftSide : public Side<T>
{
};
template<class T>
struct RightSide : public Side<T>
{
};
Side<int>* f(int left, int right)
{
return left < right ? new LeftSide<int> : new RightSide<int>;//<---Here I'm returning either left or right side
}
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
I'm getting an error:
_Error 1 error C2446: ':' : no conversion from 'RightSide *' to 'LeftSide *'_
I've thought (wrongly as I see) that I can assign pointer from derived to base without any problems. So where is the problem?
The problem is not with the conversion from either LeftSide or RightSide to Side<T>. As you originally thought, this conversion would be fine.
Rather, the problem is with this expression:
left < right ? new LeftSide<int> : new RightSide<int>
Let's break this down a little. The ternary operator (properly referred to in the Standard as the 'comparison operator') looks like this:
bool_val ? lhs_expression : rhs_expression
Keep in mind that this whole construct is itself an expression. Meaning it returns a value, which has to have a type, obv. The type of the whole expression is deduced from the types of lhs_expression and rhs_expression. In this case, you have a LeftSide and a RightSide. So, here's your problem.
LeftSide and RightSide are not directly related to each other other than having a common base class, and there's no conversion available between them. (You'd have to write one.) So there's no single datatype that the bool_val ? lhs_expression : rhs_expression can have. You might think, "well, silly compiler, why not just figure out the common base class and use that?" This is, indeed, a bit of a pain. Leaving the argument of it being Right or Wrong aside, it just doesn't work that way.
You have two options.
One, use a simpler construct:
if( left < right )
return new LeftSide<int>;
else
return new RightSide<int>;
Two, if you really really want to use the ternary operator (which is the case sometimes), you need to spoon-feed the compiler it's datatypes:
Side<int>* f(int left, int right)
{
return left < right ? static_cast<Side<int>*>(new LeftSide<int>) : static_cast<Side<int>*>(new RightSide<int>);// now you're good
}
I think that the ? : operator requires that the 2 choices be the same type; not that they can be converted to the same type
FYI gcc fails the same
error: conditional expression between distinct pointer types ‘LeftSide<int>*’ and ‘RightSide<int>*’ lacks a cast
casting both to Side(int)* works (but you probably knew that already)
You want both branches to return a Side<int>*, but the compiler doesn't know that, the type Side<int> doesn't appear anywhere in that expression.
Since I don't like to use a cast when an implicit conversion exists, I'd write this as:
if (left < right) return new LeftSide<int>;
return new RightSide<int>;
But if you want to use a ternary operator,
Side<int>* i_want_this_type;
return (left < right) ? new LeftSide<int> : (i_want_this_type = new RightSide<int>);
Now the right hand branch is type Side<int>*, the left hand is convertible to that type, everything is ok (and the compiler optimizes out the extra variable).
The two should be the same type, or one should be convertible to the other.
return left < right ? (Side<int>*)new LeftSide<int> : (Side<int>*)new RightSide<int>;
Related
I'm creating an interpreter of a particular language in C++. After creating a parser, implementing scope resolution etc., the only problem I have is implementing dynamically typed variables.
Following some general advice scattered around, I created VarData and VarType structs:
union VarData{
int IntData;
char CharData;
double DoubleData;
};
enum class VarType {
Int,
Char,
Double
};
and a variable struct (it is obviously incomplete):
struct Variable {
VarData data;
VarType type;
template<typename T>
void operator =(T val) {
std::string name = typeid(T).name();
if (name == "char") {
data.CharData = val;
type = VarType::Char;
}
else if (name == "int") {
data.IntData = val;
type = VarType::Int;
}
else if (name == "double") {
data.DoubleData = val;
type = VarType::Double;
}
}
};
And this actually kind of works, for instance in this sample code, all assigned values are correctly stored:
int main() {
Variable a;
a = '5'; // a.type is now VarType::Char
a = 57; // a.type is now VarType::Int
a = 8.032; // a.type is now VarType::Double
}
The problem I have is that if I want to use the Variable struct, I need operator overloads for all common operators (+, -, /, * etc.), each of which needs to cover all possible pairs of types Variable can take. For instance,
Variable operator + (Variable& v1, Variable& v2) {
if (v1.type == VarType::Char && v2.type == VarType::Char)
//return Variable of type int
else if (v1.type == VarType::Double && v2.type == VarType::Int)
// return Variable of type double
else if (...)
}
Is there any other (not involving millions of nested if statements) method of doing that?
Sorry if my question is not exactly clear, I will be happy to provide additional explanation.
One way to handle all the different possible type combinations could be to use double dispatch to execute the operation based on the types involved.
Double dispatch would simplify the determination of what variant of the operation to execute. This means a lot of if less, leaving either to some clever combination of overload override or a dispatch table the duty to mechanically find the suitable operation. However, it would not really be a mastery of the combinatorial explosion.
Another more effective way would be to apply some systematic type promotion rules. For example if you want to combine in one operation an integer and a float, you'd convert everything to float before performing the operation.
If you use the interpreter pattern, you could have a template method pattern to manage the type promotion before invoking the suitable operator overload for two values of the same type.
Unrelated but important: you need to be aware that the typeid() is not a standardized value. So "int", "double", etc... are a nice implementation, but other strings might be used for other compilers. This makes your code non-portable
I have such expressions in my code:
QByteArray idx0 = ...
unsigned short ushortIdx0;
if ( idx0.size() >= sizeof(ushortIdx0) ) {
// Do something
}
But I'm getting the warning:
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if ( idx0.size() >= sizeof(ushortIdx0) ) {
~~~~~~~~~~~~^~~~~~~~~~
Why size() of QByteArray is returned as int rather than unsigned int? How can I get rid of this warning safely?
Some folk feel that the introduction of unsigned types into C all those years ago was a bad idea. Such types found themselves introduced into C++, where they are deeply embedded in the C++ Standard Library and operator return types.
Yes, sizeof must, by the standard, return an unsigned type.
The Qt developers adopt the modern thinking that the unsigned types were a bad idea, and favour instead making the return type of size a signed type. Personally I find it idiosyncratic.
To solve, you could (i) live with the warning, (ii) switch it off for the duration of the function, or (iii) write something like
(std::size_t)idx0.size() >= sizeof(ushortIdx0)
at the expense of clarity.
Why size() of QByteArray is returned as int rather than unsigned int?
I literally have no idea why Qt chose a signed return for size(). However, there are good reasons to use a signed instead of an unsigned.
One infamous example where a unsigned size() fails miserably is this quite innocent looking loop:
for (int i = 0; i < some_container.size() - 1; ++i) {
do_somehting(some_container[i] , some_container[i+1] );
}
Its not too uncommon to make the loop body operate on two elements and in that case its seems to be a valid choice to iterate only till some_container.size() - 1.
However, if the container is empty some_container.size() - 1 will silently (unsigned overflow is well defined) turn into the biggest value for the unsigned type. Hence, instead of avoiding the out-of-bounds access it leads to the maximum out of bounds you can get.
Note that there are easy fixes for this problem, but if size() does return a signed value, then there is no issue that needs to be fixed in the first place.
Because in Qt containers (like: QByteArray, QVector, ...) there are functions which can return a negative number, like: indexOf, lastIndexOf, contains, ... and some can accept negative numbers, like: mid, ...; So to be class-compatible or even framework-compatibe, developers use a signed type (int).
You can use standard c++ casting:
if ( static_cast<size_t>(idx0.size()) >= sizeof(ushortIdx0) )
The reason why is a duplicate part of the question, but the solution to the type mismatch is a valid problem to solve. For the comparisons of the kind you're doing, it'd probably be useful to factor them out, as they have a certain reusable meaning:
template <typename T> bool fitsIn(const QByteArray &a) {
return static_cast<int>(sizeof(T)) <= a.size();
}
template <typename T> bool fitsIn(T, const QByteArray &a) {
return fitsIn<T>(a);
}
if (fitsIn(ushortIdx0, idx0)) ...
Hopefully you'll have just a few kinds of such comparisons, and it'd make most sense to DRY (do not repeat yourself) and instead of a copypasta of casts, use functions dedicated to the task - functions that also express the intent of the original comparison. It then becomes easy to centralize handling of any corner cases you might wish to handle, i.e. when sizeof(T) > INT_MAX.
Another approach would be to define a new type to wrap size_t and adapt it to the types you need to use it with:
class size_of {
size_t val;
template <typename T> static typename std::enable_if<std::is_signed<T>::value, size_t>::type fromSigned(T sVal) {
return (sVal > 0) ? static_cast<size_t>(sVal) : 0;
}
public:
template <typename T, typename U = std::enable_if<std::is_scalar<T>::value>::type>
size_of(const T&) : val(sizeof(T)) {}
size_of(const QByteArray &a) : val(fromSigned(a.size())) {}
...
bool operator>=(size_of o) const { return value >= o.value; }
};
if (size_of(idx0) >= size_of(ushortIdx0)) ...
This would conceptually extend sizeof and specialize it for comparison(s) and nothing else.
#include <cstdint>
#include <iostream>
uint32_t ReadInt() { return 0; }
uint64_t ReadLong() { return 0; }
template<class SizeType>
class MyType
{
public:
SizeType Field;
MyType()
{
Field = sizeof(SizeType) == 8 ? ReadLong() : ReadInt();
}
};
int main()
{
MyType<uint32_t> m;
std::cout << m.Field;
}
I get a compiler warning because it looks like the the condition sizeof(MyType) == 4 is not being evaluated at compile time.
If it were we would have specialization and this wouldn't be a problem.
Anyway I could achieve this?
EDIT: What I really want to achieve is this:
Field = ReadLong();
OR
Field = ReadInt();
through template meta-programming. Can I do this without specializing the Read* functions? Given how powerful c++ templates I really feel like I'm missing some aha moment, because if I have to specialize Read* functions the rabbit hole continues to go deeper.
warning C4244: '=': conversion from 'int64_t' to 'uint32_t', possible loss of data for the int specialization
I get a compiler warning because it looks like the the condition sizeof(MyType) == 4 is not being evaluated at compile time.
No, it doesn't look like that at all. Whether the comparison is evaluated at compile time or not has no effect on the return type of the conditional expression.
If we simplify the example by removing the conditional and expand the template using the type that you used, we get this minimal reproduction:
uint32_t Field;
int64_t temp = ReadInt(); // temporary variable for exposition
Field = temp;
Clearly, the int64_t may contain a value that is much greater than can be represented by int32_t. If it does, then the correct value will be lost in conversion. The compiler warns about this possibility.
Why is the type of the conditional int64_t specifically you might ask. Well, the types of each subexpression is int64_t and uint32_t respectively, so the type must be one of those. The type of Field or the result of the comparison - even if evaluated at compile time - has no effect on which type is chosen. Instead, integral promotion rules are used in this case.
Anyway I could achieve this?
A template function should work:
template<class T>
T Read() {
static_assert(false, "not implemented");
}
template<>
uint64_t Read<uint64_t>() {
return ReadLong();
}
template<>
uint32_t Read<uint32_t>() {
return ReadInt();
}
// ...
Field = Read<SizeType>();
I get a compiler warning because it looks like the the condition sizeof(MyType) == 4 is not being evaluated at compile time
Wrong, it is evaluated at compile-time, but the conditional operator still has the bigger result-type of the arguments.
To fix it, just add a cast:
Field = sizeof(SizeType) == 8 ? (SizeType)ReadLong() : ReadInt();
Another approach using overload-resolution:
long ReadData(long) { return ReadLong(); }
int ReadData(int) { return ReadInt(); }
Field = ReadData(SizeType());
A conditional operator ?: expression evaluates to a single type, which accommodates both possible internal-to-the-construct result types.
This happens even when it's evaluated at compile time.
The common type in your case is the largest of the two possible integer types.
template<typename T> T SmartIO::Peek() {
T temp;
T tempReturn;
while(true){
temp = *(T*)&buffer[ptrSeek];
if(temp !=0){
ptrSeek++;
tempReturn += *(T*)&buffer[ptrSeek];
}
else{
break;
}
}
return tempReturn;
}
so what i want to do is , start reading from ptrSeek start looping, adding the value to temp and check if temp's value !=0 add this value to tempReturn, and once the temp's value is 0 break the loop and return the tempReturnbut, but it's keep giving me this error :
error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'std::basic_string<_Elem,_Traits,_Ax>' (or there is no acceptable conversion)
how can i solve this issue here?
There is a fundamental issue with your template code if you are attempting to compare an arbitrary type T against the numeric constant 0, which you are doing in the code here:
T temp;
/* ... */
if(temp != 0){
/* ... */
}
The problem here is that T is an arbitrary type (in this case, you seem to be instantiating the template with std::string), but you are expecting that type to be comparable to 0. This is perfectly fine - it just restricts T to be types that can be compared against 0 - but from the fact that you're reporting this as an error I'm not sure if you're aware of this.
Your options are either to not instantiate this template with std::string as an argument (the way it's written, I don't think you're supposed to be able to do this, since it looks like the function keeps adding values together of some type), or to debug the template and change its behavior. I'm not quite sure what you want the code to do, so in the latter case I'm not sure how I can assist.
Hope this clarifies things!
You can specialize or overload the comparison part (here !=) for the types which are not directly comparable to 0. Just an example,
template<typename T>
bool NotEqualto0 (const T& obj) { return (obj != 0); }
// overload for std::string
bool NotEqualto0 (const std::string &s) { return (s.c_str() != 0); }
...
if(NotEqualto0(temp))
...
[Above function is hardwired for 0; it can be generalized as per need.]
I have a enumerated type StackID, and I am using the enumeration to refer to an index of a particular vector and it makes my code easier to read.
However, I now have the need to create a variable called nextAvail of type StackID. (it actually refers to a particular stackID ). I tried to increment it but in C++, the following is illegal:
nextAvail++;
Which sort of makes sense to me ... because there's no bounds checking.
I'm probably overlooking something obvious, but what's a good substitute?
I also want to link to this question.
I'm probably overlooking something obvious, but what's a good substitute?
Overloading operator++:
// Beware, brain-compiled code ahead!
StackID& operator++(StackID& stackID)
{
#if MY_ENUMS_ARE_CONTIGUOUS && I_DO_NOT_WORRY_ABOUT_OVERFLOW
return stackID = static_cast<StackID>( ++static_cast<int>(stackID) );
#else
switch(stackID) {
case value1 : return stackID = value2;
case value2 : return stackID = value3;
...
case valueN : return stackID = value1;
}
assert(false);
return stackID; // some compilers might warn otherwise
#endif
}
StackID operator++(StackID& stackID, int)
{
StackID tmp(stackID);
++stackID;
return tmp;
}
Because enumerations do not have to be contiguous. E.g. take this example:
enum Colors {
cRed, // = 0
cBlue, // = 1
cGreen = 3
}
What should happen in this scenario?
Colors color = cBlue;
Colors other = color++;
Should other be cGreen or should it be 2. In that case it's not a valid enumeration member anymore. What about this?
Colors color = cGreen;
Colors other = color++;
Should other be cRed (wrap around) or 4?
As you can see, being able to increment enumeration values introduces a whole lot of questions and complicates the simple mechanism that they intend to be.
If all you care about is the integer value being incremented, then simply cast to int and increment that.
Casting back and forth to/from int is of course the obvious solution, then you make clear that you understand that the addition is happening "outside" the enum:
nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1);
Why not store nextAvail as an int instead if you're going to do arithmetic operations on it?
Another option would be to wrap the enum in your own type and overload operator ++ for it (which also could wrap around or something for instance).
An enumeration is semantically supposed to represent a set of distinct related, values.
So you could have
enum Colour {RED, GREEN, BLUE};
But that should be equivalent to:
enum Colour {GREEN, BLUE, RED};
The problem is that if you increment an enum then those representations are not the same. GREEN++ in the first case is not the same as GREEN++ in the second.
Making your program dependent on the declaration of the enum is a recipe for disaster - maintainers may assume that the order of the enum doesnt matter, introducing many silent bugs.
Very Simple:
nextAvail = (StackID)(nextAvail + 1);
Enums are going to be type int, so you can cast them. Is this what you're trying to do?
int ndx = (int) StackID.SomeValue;
...
++ndx;
This is going to make someone very confused down the line, of course.
It occurs to me that you're using an enum where you should be using const, or even #define. enum is most appropriate when you have arbitrary values (where the exact value is not meaningful).
I've overloaded the ++/-- operator in this way:
enum STATE {STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6};
// Overload the STATE++ operator
inline STATE& operator++(STATE& state, int) {
const int i = static_cast<int>(state)+1;
state = static_cast<STATE>((i) % 6);
return state;
}
// Overload the STATE-- operator
inline STATE& operator--(STATE& type, int) {
const int i = static_cast<int>(type)-1;
if (i < 0) {
type = static_cast<STATE>(6);
} else {
type = static_cast<STATE>((i) % 6);
}
return type;
}
With respect to oprator++, $5.2.6/1 states- "The type of the operand shall be an arithmetic type or a pointer to a complete object type."
StackID does not fit the bill here. It is of enumeration type.
One option is like this
$5.7/1 - "For addition, either both operands shall have arithmetic or enumeration type, or one operand shall be a pointer to a completely defined object type and the other shall have integral or enumeration type."
enum Possibility {Yes, No, Maybe};
Possibility operator++(Possibility const& r){
return Possibility(r + 1); // convert r to integer, add 1, convert back to Enum
}
int main(){
Possibility p = Yes;
Possibility p1 = ++p;
}
I'm quite happy with this C plus C++ solution for a for loop incrementing an enum.
for (Dwg_Version_Type v = R_INVALID; v <= R_AFTER; v++)
=>
int vi;
for (Dwg_Version_Type v = R_INVALID;
v <= R_AFTER;
vi = (int)v, vi++, v = (Dwg_Version_Type)vi)
The other solutions here are not C backcompat, and quite large.