-5

I'm comparing two pointers of class typedef value_type which are each of type T* or char16_t.

The compiler complains that I can't compare the two because they are distinct types:

'some_type1<char16_t>::value_type*' and 'some_type2<char16_t>::value_type*' lacks a cast

Strangely, I can't static_cast<> between the two:

invalid static_cast from type 'some_type1<char16_t>::value_type*' to type 'char16_t*'

Does it make a difference whether I use reinterpret_cast<> to compare or just static_cast<> both sides to void*?

I read somewhere that reinterpret_cast<> is done at runtime but I'm not sure.

UPDATE

I was under the false impression that reinterpret_cast<> was done at runtime. With further discussion I now understand that it is purely a compile-time construct.

Curiously though, it's also been demonstrated that static_cast<> can have runtime costs where a particular object is cast into another by matching against a constructor.

For exmaple, you can cast a primitive int to a vector with static_cast<>. It would seem that this is true for all cases where static_cast<T>(e) would be valid.

Zhro
  • 2,546
  • 2
  • 29
  • 39
  • Slower? It's all done during compilation, do you really care how long it takes for the compiler to do the job? – barak manos Feb 16 '16 at 19:00
  • 3
    Please [edit] your question to include a [mcve] and clarify the problem. For example, the following conflicts with itself; `char16_t` cannot be equivalent to a pointer type: _which are each of type `T*` or `char16_t`_ – chris Feb 16 '16 at 19:04
  • If you are ever not sure you should check the [Documentation](http://en.cppreference.com/w/cpp/language/reinterpret_cast). Yes there may be errors with it(i have seen 2 in the years I have used it) but it is a good place to start if you do not remember how something works. – NathanOliver Feb 16 '16 at 19:09
  • When you refer to a pointer of the `char16_t`, do you mean `char16_t*`? The former is an integer type, not a pointer. – Pete Becker Feb 16 '16 at 19:10
  • It is unclear what you are trying to achieve. The two pointers are completely unrelated, so what does casting one to another and than comparing gives you? – SergeyA Feb 16 '16 at 19:10
  • I was trying to silence the compiler error. – Zhro Feb 16 '16 at 19:13
  • @Zhro, not a valid goal by any means. You need to re-adjust your attitude towards compiler errors and warnings - they are your best friends. Trully. – SergeyA Feb 16 '16 at 19:17

3 Answers3

4

reinterpret_cast<> is purely a compile-time cast. You're just reinterpreting what the underlying type is, completely sidestepping the type system. There is no possible runtime aspect.

static_cast<> can have a runtime cost, depending on what it is you're static_cast-ing. If you're casting a void*, or through an non-polymorphic object hierarchy, there will be no runtime cost. If you're casting through a polymorphic object hierarchy, there will be offset changes due the vtable which have to happen at runtime.

And if you're casting outside of a hierarchy, then you have to actually create a new object. Whether that looks like calling a conversion function:

struct A {
    operator B() { /* something */ }
};

A a;
static_cast<B>(a);

Or a converting constructor:

static_cast<std::vector<int>>(4);

that static_cast<> creates a whole new object - so definitely some code will need to be run to do this!

Barry
  • 286,269
  • 29
  • 621
  • 977
  • I didn't know you could `static_cast<>` primitive types to objects. Is it just looking at each constructor for a compatible type? – Zhro Feb 16 '16 at 19:31
  • @Zhro `static_cast(e)` is valid iff `T t(e)` is valid. – Barry Feb 16 '16 at 19:34
  • Nice. Does the last statement also apply when casting a floating point instance to a fixed point instance or vice-versa? – barak manos Feb 16 '16 at 19:47
  • @barakmanos You mean like `static_cast(2.0)`? Yeah, that has to do *something* – Barry Feb 16 '16 at 19:48
  • Well, I was actually thinking of the old C-style cast. I've always wondered how it was possible to perform that cast without actually changing the "bit-contents" of the operand during runtime. – barak manos Feb 16 '16 at 19:50
  • @barakmanos C-style cast tries to do lots of different casts. If you did `(int)2.0` that would end up doing a `static_cast`. – Barry Feb 16 '16 at 19:55
3

Even when no custom type conversion logic is involved, static_cast might have a (unnoticeable) run-time performance. This is due to the fact that in case of multiple inheritance, static_cast needs to adjust offsets to bases, and this would require run-time arithmetics. While the effect is trully miniscule, it is there. It is clear from the following code sample:

struct Mother {
  virtual ~Mother(); 
  virtual void mother();
};

struct Father { 
  virtual ~Father();
  virtual void father();
};

struct Offspring: Mother, Father {
  void mother();
  void father();
};

void foo(Offspring* offspring) {
  Mother* mother = offspring;
  mother->mother();
}

The ASM code for function foo() has following piece of line:

movq    %rax, -8(%rbp)

That is the base offset. If you remove the cast, you will see this line disappearing.

On the other hand, reinterpret_cast is trully compile-time only cast and has no effect whatsoever during program run.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
2

I read somewhere that reinterpret_cast is done at runtime but I'm not sure.

No, that's wrong (from what ever source you've got that).

reinterpret_cast<> and static_cast<> are both resolved at compile time (as you see from the compiler error).

static_cast<> is slightly slower than reinterpret_cast<> because some calculations for the offsets against the base class needs to be inserted in the emitted code.

May be you were confusing that with dynamic_cast<> which is indeed done at runtime, and performing a bit slower than a reinterpret_cast<> or static_cast<>.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • This answers the question by invalidating the premise. I don't know where I read this but I couldn't find a source confirming whether it was runtime or compile-time. It may have been a false assumption against `static_cast` being compile-time. – Zhro Feb 16 '16 at 19:08
  • Your last statement pretty much contradicts the rest of your answer IMO. How can you compare the speed of two elements which are running in two different scopes? – barak manos Feb 16 '16 at 19:08
  • @barakmanos Doesn't dynamic cast have to be slower since it is done at run time. Any cast done at compile time cost 0 at run time. – NathanOliver Feb 16 '16 at 19:10
  • Makes sense. Whether the premise was invalid or not, I wasn't able to find an answer by searching. This question is still useful for anyone else who might be confused on the subject. I think downvoting it is a bit harsh. – Zhro Feb 16 '16 at 19:10
  • @barakmanos How's that contradictorily? `dynamic_cast` is done at runtime and emits more code that will perform slower. – πάντα ῥεῖ Feb 16 '16 at 19:11
  • You do answer question literally, but I doubt it actually does any service to OP :) – SergeyA Feb 16 '16 at 19:11
  • @NathanOliver: The speed of compilation-time casts during runtime is zero **by definition** (and as pretty rightfully noted by the author). I just think that the comparison is pointless to begin with. – barak manos Feb 16 '16 at 19:12
  • 3
    You can't say that `static_cast` has no effect during runtime. It does. – SergeyA Feb 16 '16 at 19:13
  • static_cast is **not** a compile-time only cast. – SergeyA Feb 16 '16 at 19:14
  • @SergeyA: As Zhro, I also don't understand this statement (except, perhaps, when casting from floating point types to fixed point types). – barak manos Feb 16 '16 at 19:15
  • @barakmanos, the statment *have any impact on performance at runtime* is plain wrong. – SergeyA Feb 16 '16 at 19:16
  • @SergeyA: Please explain by an example of a compilation-time cast which yields an additional code. – barak manos Feb 16 '16 at 19:17
  • @SergeyA: Right... I would really love to see that the generated assembly of your example actually contains an additional piece of code (not being sarcastic of course, just a little doubtful). I believe that `static_cast` should generate a compilation error if the cast requires such thing as offset adjustment (thus justifying its "static-ness"). – barak manos Feb 16 '16 at 19:19
  • 3
    @barakmanos `struct A { operator B() { /* do lots of stuff here */; } }; A a; static_cast(a);` would do stuff. – Barry Feb 16 '16 at 19:22
  • @Barry Overloading option of the cast operator is a pretty good point. – πάντα ῥεῖ Feb 16 '16 at 19:24