Search code examples
c++overheadstatic-cast

Can static_cast to same type introduce runtime overhead?


I have a structure template that takes two types (T and S), and at some point uses a static_cast to convert from one type to the other. It is often the case that T and S are the same type.

A simplified example of the setup:

template <typename T, typename S = T>
struct foo
{
  void bar(T val)
  {
    /* ... */
    some_other_function(static_cast<S>(val));
    /* ... */
  }
};

In the case that S is the same class as T, does or can the static_cast introduce extra overhead, or is it a null operation which will always be ignored?

If it does introduce overhead, is there a simple template metaprogramming trick to perform the static_cast only if needed, or will I need to create a partial specialization to cope with the T == S case? I'd rather avoid the partial specialization of the entire foo template if possible.


Solution

  • Yes, it can.

    Here is an example:

    struct A {
      A( A const& ) {
        std::cout << "expensive copy\n";
      }
    };
    
    template<typename T>
    void noop( T const& ) {}
    template <typename T, typename S = T>
    void bar(T val)
    {
      noop(static_cast<S>(val));
    }
    template <typename T>
    void bar2(T val)
    {
      noop(val);
    }
    int main() {
      std::cout << "start\n";
      A a;
      std::cout << "bar2\n";
      bar2(a); // one expensive copy
      std::cout << "bar\n";
      bar(a); // two expensive copies
      std::cout << "done";
    }
    

    basically, a static_cast can induce a copy constructor to be called.

    For some types (like int), a copy constructor is basically free, and the compiler can eliminate it.

    For other types, it cannot. In this context, copy elision isn't legal either: if your copy constructor has side effects or the compiler cannot prove that it has no side effects (common if the copy constructor is non-trivial), it will be called.