Clang Warning on expression side effects
Asked Answered
M

1

26

Given the following source code:

#include <memory>
#include <typeinfo>

struct Base {
  virtual ~Base();
};

struct Derived : Base { };

int main() {
  std::unique_ptr<Base> ptr_foo = std::make_unique<Derived>();

  typeid(*ptr_foo).name();

  return 0;
}

and compiled it with:

clang++ -std=c++14 -Wall -Wextra -Werror -Wpedantic -g -o test test.cpp

Enviroment setup:

linux x86_64
clang version 5.0.0

It does not compile because of warning (note -Werror):

error: expression with side effects will be evaluated
      despite being used as an operand to 'typeid'
      [-Werror,-Wpotentially-evaluated-expression]
  typeid(*ptr_foo).name();

(Just a note: GCC does not claim that kind of potential problematic)


Question

Is there a way to get the information about the type pointed by a unique_ptr without generating that kind of warning?

Note: I am not talking about disabling -Wpotentially-evaluated-expression or avoiding -Werror.

Magdau answered 29/9, 2017 at 18:28 Comment(4)
Note that clang is right in this case, and that warning is helpful because you might not expect a typeid call to actually have any side effects.Paleogeography
@Paleogeography - sorry, late to the party. Exactly what side-effect are we talking about? Clearly, I want the return values from the chain of methods, because I wrote them.Columbium
@Gem typeid is the only one that behaves that way. decltype and sizeof don't evaluate anything.Paleogeography
Feature creep in clang. Apart from the two @Paleogeography mentions, which aren't actually runtime functions, every other function evaluates its arguments. Given typeid works with polymorphic classes, I can't see how it could possibly work without evaluating its argument.Chalky
C
19

Looks like following should work without warnings and give correct result for derived class

std::unique_ptr<Foo> ptr_foo = std::make_unique<Bar>();

if(ptr_foo.get()){
    auto& r = *ptr_foo.get();
    std::cout << typeid(r).name() << '\n';
}
Cray answered 29/9, 2017 at 18:43 Comment(5)
Is there no 1-line solution at all? I am using a similar expression in an assert, which is macroed for internal build only, so don't really want the temporaryColumbium
you can put the temporary in a function argument: template <typename T> string get_name(const T& v) { return typeid(v).name(); } ASSERT(get_name(*ptr_foo) == "foo");Algebraist
I just ran into the same problem, and solved it with this small template helper thanks to your solution: template <typename T> char const* str_type( T const& obj ) { return typeid( obj ).name(); . As a nice bonus, it's way shorter than the original summon, but, it only works for valid pointers (othewise, this derefs a nullptr, but it's easy enough to avoid).Incardination
Is there any explaination for it? Why directly typeid(*ptr_foo.get()).name() won't work?Paramedic
@Paramedic Because people mostly think typeid does not evaluate the expression. For an expression returning a polymorphic object, the compiler has to generate code to evaluate the expression. It is valid C++ code (so GCC does not warn), but people may not be aware of the consequences. Clang will warn when this happens. The solutions all make the expression evaluation outside typeid, and both the compiler and human readers should see there are no surprises.Fanfani

© 2022 - 2025 — McMap. All rights reserved.