2

We have a method which is being passed a class as an argument. This class has different child classes. We need to know which of those classes is the one who is being passed as an argument to this method. We can't define one method for each of the possible classes due to assignment requirements. Furthermore, if the child class isn't supported by this method, the error must be thrown in compile time. We've been trying to do this using static_cast but we are not obtaining the required results as the conversion between the two child classes is always possible.

class A{
...
};

class B : public A{
...
};

class C : public A{
...
}

void foo(A a){
    if(a is B){
        //OK and do stuff
    }else if(a is C){
        //throw compile error
    }
}
pitazzo
  • 1,125
  • 1
  • 13
  • 28
  • [`dynamic_cast`](https://en.cppreference.com/w/cpp/language/dynamic_cast)? ...And by the way, used like that, your function `foo` will suffer from [`object slicing`](https://stackoverflow.com/questions/274626/what-is-object-slicing); in general you want to pick up a good [C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – WhiZTiM May 05 '18 at 11:04
  • You need to pass pointers, not objects, to prevent slicing away the child info. – Barmar May 05 '18 at 11:08
  • 1
    @WhiZTiM How would dynamic cast help? You have to know which child it is before you cast it, but the object here is to find out which child it is. – Barmar May 05 '18 at 11:08
  • @Barmar Maybe like this? https://ideone.com/HV8gs3 – Killzone Kid May 05 '18 at 11:16
  • Isn't it undefined behavior to dynamic cast to a type that isn't what it actually points to? – Barmar May 05 '18 at 11:17
  • 2
    @Barmar, To find out which class instance a *pointer* or *reference* to an object is at runtime, there are two language facilities for that, `dynamic_cast` or `typeid`; with `dynamic_cast`, the OP can try to match it's results against a closed set of types known, and if the cast fails, it returns a `nullptr` for *pointer* casts, else throws [`std::bad_cast`](http://en.cppreference.com/w/cpp/types/bad_cast) for *reference* casts. And no, `dynamic_cast` is the softest landing, it never invokes UB; (unless you work hard to get it do so) – WhiZTiM May 05 '18 at 11:18
  • 1
    *"error must be thrown in compile time"* sounds like a job for a template function. – user7860670 May 05 '18 at 11:19
  • 1
    Actually a normal function would be fine too `void foo(C const &) = delete;`. Not sure whether this is acceptable though. As currently written in question checks inside `foo` function are useless because type of `a` would be always `A`. So it is difficult to guess what `foo` is supposed to do. – user7860670 May 05 '18 at 11:24
  • Since you want a compile error if `a` is `C`, this looks like a job for templates. – Eljay May 05 '18 at 11:48

1 Answers1

1

You can write foo itself as a template for doing all the checks at compile time:

#include <type_traits>

template<class T>
void foo(T t)
{
  static_assert(std::is_same<T, C>::value == false,
                "foo() must not be invoked with object of class C");
  if (std::is_same<T, B>::value) {
    // do stuff
  }
}

static_assert is used for compile time checks of some condition and std::is_same compares two types at compile time.

piripiri
  • 1,925
  • 2
  • 18
  • 35