GCC "changes meaning" error

Hi,

The following code compiles just fine on both Clang and MSVC, but fails on GCC.

1
2
3
4
5
6
struct Test {};
     
struct Foo
{
    Test Test;
};



prog.cpp:5:7: error: declaration of 'Test Foo::Test' [-fpermissive]
  Test Test;
       ^
prog.cpp:1:8: error: changes meaning of 'Test' from 'struct Test' [-fpermissive]
 struct Test {};
        ^


Honestly, I think this is stupid as hell. Coming up with meaningful names is hard, and I don't want to have to rule out the clearest one just because there's already a type with that name. I get how it may cause some ambiguity with functions and types that overload the function call operator, but other than that I don't care. I have two questions here:

1) Why does GCC error out on this, while the other compilers don't say anything, even with maximum warning levels enabled?
2) I can bring it down to a warning by using -fpermissive, but from what I can tell that's it. I want to get rid of the warning completely because I think it's stupid. How can I do that (without changing my code, because again: stupid)?
Last edited on
1. Most likely, you're not really enabling maximum warning levels. VC++ is also known to be supremely liberal in what it accepts (I actually just had a case where it allowed a class to be copied despite explicitly deleting the copy constructor. It baffled me but is an extension which allows objects to be constructed using copy constructor syntax while really using the default or explicit constructors).

2. It's going to give you a warning because it's horrid practice, almost agreed upon on a global community level. I can't imagine why you can't just use "Test test" where it's easy to tell the difference simply because of capitalization.

EDIT: I am curious as to what the standard says about it though.
Last edited on
1
2
3
4
5
6
struct Test {};
     
struct Foo
{
   struct Test Test; // elaborated-type-specifier: work-around for g++
};
The standard says

3.3.7[basic.scope.class]

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.


You can also fix that struct by changing it to

1
2
3
4
struct Foo
{
    ::Test Test;
};

Last edited on
Prepending with "struct" or "::" fixes cases where the the field and its type share the same name, but not cases where the field shares a name with a different type. What can I do for that?

it's horrid practice, almost agreed upon on a global community level

I don't think so. The official coding style guides for Epic Games, Microsoft, LLVM, and more all suggest using Pascal Case for types and field names, which inevitably leads to collisions (and most languages are totally fine with that, except C++ apparently); though ultimately it comes down to personal preference.
Last edited on
> cases where the field shares a name with a different type. What can I do for that?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <type_traits>

struct test {};
test test ;

namespace A
{
    struct test {};

    struct foo
    {
        struct test test_one ; // elaborated-type-specifier
        A::test test_one_a = test_one ; // qualified name
        decltype(test_one) test_one_b = test_one_a ;

        int test = 12345 ; // fine: the unadorned (bare) name 'test' is not used in any declaration
                           // in this class, other than in this declaration

        struct test test_two = test_one ; // fine: elaborated-type-specifier
        A::test test_three = test_two ; // fine: qualified name
        struct ::test test_four ; // fine: elaborated-type-specifier + qualified name
        // ::test test_five ; // *** error: '::test' is not the name of a type

        static_assert( std::is_same< A::test, decltype(test_one) >::value, "unexpected type" ) ;
        static_assert( std::is_same< A::test, decltype(test_one_a) >::value, "unexpected type" ) ;
        static_assert( std::is_same< int, decltype(test) >::value, "unexpected type" ) ;
        static_assert( std::is_same< A::test, decltype(test_two) >::value, "unexpected type" ) ;
        static_assert( std::is_same< A::test, decltype(test_three) >::value, "unexpected type" ) ;
        static_assert( std::is_same< struct ::test, decltype(test_four) >::value, "unexpected type" ) ;
    };
}
Ah, thank you!

Anyway, the issue I had with the different types was more like this:

1
2
3
4
5
6
struct Test {};

struct Foo
{
    std::unique_ptr<Test> Test;
};


Which won't compile. However, if you change the declaration to "unique_ptr<::Test> Test" or "unique_ptr<struct Test> Test", then it will!

Thanks for the help
NoXzema wrote:
global community level

Does that mean the community of "all programmers" or "C++ programmers"?


IMHO unnecessary ambiguity is bad style.

Having a consistent style is good, so a style guide is good, but each point in the guide must have a rationale. MSDN guide, for example, probably targets their C#/.NET.
I'd say all where a variable name could then collide with the variable type.
Although, I wouldn't know. I've seen a few dozen styles, all cringing and usually explicitly disallowing the use of such confusing syntax. Those that don't explicitly disallow it will usually reject it upon review or be criticized later if the code base has no peer review at all and someone runs into it.

I never argued anything against consistent style. If a code base already did this, I would also follow along to be consistent. However, the idea that I'd reference "Test" and I get a compiler error screaming about how it's a type and not an identifier in specific situations is far less than ideal and confusing.

Most people do not use upper camel case variable names because it's confusing.
Topic archived. No new replies allowed.