c++typesdecltype

decltype and is_same giving confusing results


My ultimate goal is to compare the type stored within std::shared_ptr with another type (in this testcase this type is int)

int main() {
    std::shared_ptr<int> shared_ptr_to_int;

    std::cout << typeid(int).name() << std::endl;
    std::cout << typeid(decltype(*shared_ptr_to_int)).name() << std::endl;

    if (std::is_same<decltype(*shared_ptr_to_int), int>::value) {
        std::cout << "is same!\n";
    }
    else {
        std::cout << "not the same!\n";
    }
}

For my test case I am getting the result "not the same".

i
i
not the same!

Solution

  • Introduction

    When "dereferencing" a std::shared_ptr — through std::shared_ptr<...>::operator* — the result is a reference, this means that decltype(*shared_ptr_to_int) is equivalent to int&.

    A reference-to-int and int is not the same type, and as such you get the behavior which you are describing.



    Elaboration

    A dereferenced std::shared_ptr yields a reference so that one can actually reach in and modify the object that the shared_ptr is currently handling.

    In order to fix your example you should use std::remove_reference to strip away that (potentially unexpected) reference.

    if (std::is_same<std::remove_reference<decltype(*shared_ptr_to_int)>::type, int>::value) {
      ...
    }
    

    You could also pass shared_ptr_to_int as the operand of decltype and then use the result as qualifier to reach into element_type:

    if (std::is_same<decltype(shared_ptr_to_int)::element_type, int>::value) {
      ...
    }
    


    Why does typeid(...).name() return the same name for both?

    When typeid is invoked with a type which is a reference it will discard this and treat the operand as if it was a non-reference type (ie. it will simply throw away the &).

    Something else worth mentioning is that the result from invoking typeid(...).name() is implementation-defined — one should never put too much trust into the returned value. The function might even return the same name for completely distinct types — there are literally no guarantees (from the standard's point of view).

    Further reading: