0

Situation as follows: in a codebase a header which defines some types, mostly convinient shortcuts like u64 for uint64_t exists. These definitions are global, as general type definitions do not really make sense when encapsulated in a namespace. This header is used in almost any other file to unify the codebase.

Also a public availible header only library is used, which happens to define the same name. In fact the other definition is not a type but a parameter name like:

void function(uint64_t u64);

Now the compiler throws warnings about that the parameter name shadows the global type definition. Which is correct in some respect.

But as the common global type-management header is needed and the include for the library is also needed, my question is how to resolve that problem in a sane way.

Also, why a type name can be shadowed by a function parameter/argument name, as a variable name and a typename are two very different things. That sounds more like a bug in the compiler to me. Without having sound knowlege about the standard in that topic, I would assume

using mytype = unsigned int;
void myfunc(mytype mytype);

to be valid, as I just have defined a variable to have the same name as a type, but the compiler can always distinguish both, because of the syntax.


Additional Question:

why the include order of both headers seems to have no effect.

I tried to solve the problem by including the external library header first (so the global type shortcut should not exist in that module) and included the common global header which defines the types later. But the Warnings persist.


Edited to preceise the problem (2 times)

schnedan
  • 234
  • 1
  • 9
  • you may try modify the header-only library as namespace-scoped. And then you can use `using some_type = namespace_name::type` to avoid shadowed typedefs. – SHP Sep 08 '21 at 07:40
  • @SHP well the last thing I would do or want to do is to modify external code, as it would be hell to manage a local fork (I sometimes manage a set of patches to make something compatible with special embedded targets...) and update it. normaly I prefer to clone an external repository to a defined revision and use it 1:1 – schnedan Sep 08 '21 at 07:46
  • Warnings are not errors, code is valid. warning is to spot issue for following code: `void foo(mytype mytype) { mytype issue; }`. – Jarod42 Sep 08 '21 at 08:31
  • 1
    I guess the best course of action is to wrap the library header into your own header and [disable warning](https://stackoverflow.com/questions/3378560/how-to-disable-gcc-warnings-for-a-few-lines-of-code) there. And of course only include your wrapper header in the rest of the code. Or change compiler, clang does not warn about such case with `-Wshadow`. – Yksisarvinen Sep 08 '21 at 08:36
  • What is that `common global header` that contains `mostly convinient shortcuts`? Is that one created by you and only part of your project? And if so why would placing **your** convenient shortcuts in a namespace affect the external projects? (`[…]well the last thing I would do or want to do is to modify external code,[…]`) – t.niese Sep 08 '21 at 09:45
  • Btw, such name clashes are the reason why you always want to place **all** of your types and name aliases in a namespace. – t.niese Sep 08 '21 at 09:48

1 Answers1

2

But as the common global type-management header is needed and the include for the library is also needed, my question is how to resolve that problem in a sane way.

One thing you could do is to isolate the code that utilized the headers that produce that error and move it into its own compilation unit for which you silent that shadowing error message.

Also, why a type name can be shadowed by a function parameter/argument name, as a variable name and a typename are two very different things.

They are two different things, but there are cases where the syntax for both would be the same, so the compiler has to decide whether to use the parameter or the type.

Here one example, with static_assert, might be odd, but maybe there are other situations where this can be actually hard to debug:

#include <utility>

struct Type {
    constexpr bool operator == (int i) {
        return i==102;
    }
};

template <typename X>
constexpr void f1(X Type) {
  // does not fail because lambda is called which returns 101
  static_assert(Type() == 101, "");
}


void f2() {
  // fails because the operator == checks against 102
  static_assert(Type() == 101, "");
}


int main() {
  f1([] { return 101; });
  f2();

  return 0;
}

Here is probably a better example, maybe still an odd one but I could imagine that this one is more likely to occur:

bar(TypeA()); would not construct TypeA directly but TypeA operator () is called on the object of type TypeB:

#include <utility>

struct TypeA {
    void operator () () {
    }
};

struct TypeB {
    TypeA operator () () {
        return TypeA();
    }
};


void bar(TypeA a) {
}

void foo(TypeB TypeA ) {
    bar(TypeA());
}

int main() {
    foo(TypeB());
}
t.niese
  • 39,256
  • 9
  • 74
  • 101