Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8409817
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 10, 20262026-06-10T00:01:06+00:00 2026-06-10T00:01:06+00:00

I have tried the following code both with g++ and clang++ . Both cannot

  • 0

I have tried the following code both with g++ and clang++. Both cannot distinguish the type foo and the function name foo inside the body of foo. Why is this the case? Does the C++ standard mandates this? Shouldn’t the compiler at least try both?

enum foo {
    FOO = 0,
    BAR,
    BAZ
};

class Bar {
    public:

    foo foo () const
    {
        // does not compile if I write static_cast<foo>(...)
        return static_cast< ::foo>(m_bar);
    }

    int m_bar;
};

int main ()
{
    Bar bar;
    bar.m_bar = 0;
    foo foo_bar = bar.foo(); 
    return 0;
}

I can replace ::foowith enum foo, and it will compile just fine. However, if I change enum foo {...} to typedef enum _foo {...} foo, the same problem remains (http://ideone.com/d1GiO).

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-10T00:01:08+00:00Added an answer on June 10, 2026 at 12:01 am

    In C and in C++ (this was inherited) there are two separate identifier spaces: one for general symbols, including variables, functions… and a separate one for user defined types (enums, structs). A typedef expression creates an alias to a user defined type inside the general identifier space.

    Because the identifier spaces are kept separate, the language allows you to define a function and a type of the same name even in the same context:

    enum foo { no, yes };
    void foo() {}
    

    In C you were forced to qualify identifiers in the user defined types space explicitly, so in the previous example, to use the foo type you would have to do enum foo:

    void foo( enum foo ) {} 
    

    Now, a typedef creates an alias in the global identifier space, so by using a typedef you can get away without qualification:

    typedef enum bar { no, yes } bar;
    void foo( bar ) {}                     // uses the typedef
    

    Moving forward in time to C++[*], both identifier spaces are still in the language, what has changed are the lookup rules. When looking for an identifier in the global identifier space (i.e. without a preceding enum, struct or class keyword, and in a context where non-types are allowed), the compiler will start lookup from the inner most scope to the outer scope, and for each scope it will lookup first in the global identifier space, and if nothing is found there, then it will also look in the user defined types. This is what makes the enum, struct or class optional. In most cases, that is.

    In your particular case, you are doing a couple of things that can make the outcome surprising. First, you have a declaration that uses the same identifier to refer to two different things. This is fine, because until the name of the function is reached, the only entity called foo is the enum:

    foo         // No need for 'enum', at this point function 'foo' is not declared
    foo();      // No collision, this is 'foo' in global id space, not 'enum foo'
    

    Now, inside Bar::foo, if you use foo by itself it will start looking in the scope of the function, where it will not find anything. It will then move out to the Bar class scope, where it will see that there is a foo function and lookup will stop there. Note that whether you have the typedef or not for the enumerator does not make a difference, as lookup stops before leaving the Bar class, and thus before potentially finding either identifier at namespace level.

    As you noted, if you add the enum keyword, then suddenly you change the rules. You are now looking for a user defined type, and the search will follow the same scopes, but will only look in the identifier space for user defined types. So it will go out of Bar::foo, into Bar, where there is no enum foo, so it will continue outwards until it finds the enumeration at namespace level.

    If you provide namespace qualification, the same thing happens: prepending foo with :: requires lookup to start at the global namespace level. In that level, the only foo that is defined is the user defined type enum foo. Note that this is orthogonal to the adding or not the enum keyword. In the original code, you could have a function foo at namespace level, and that would cause a similar issue:

    enum foo { no, yes };
    void foo() {}
    class Bar {
       foo foo() {                            // Error [1]
          return static_cast<::foo>(0);       // Error [2]
       }
    };
    

    In this example there are two errors. When declaring the return type, the function Bar::foo is not yet declared, but there is ::foo(), and following the rules above lookup will go outwards until the global namespace and find ::foo() before checking for enum foo. The second error, which is the basically the same, is that the qualification in the static_cast requesting the global namespace will not help here. The reason is that lookup will again find ::foo() before it finds enum foo. The correct code for this would be:

    class Bar {
       enum foo foo() {
          return static_cast<enum ::foo>(0);  // :: is optional!
       }
    };
    

    In this case, the namespace qualification is again optional, but only because there is no foo user defined type that will be found by lookup. But we can make the code a bit more convoluted…

    enum foo { no, yes };
    void foo() {}
    class Bar {
       struct foo {};
       enum ::foo foo() { 
          return static_cast<enum ::foo>(0);
       }
    };
    

    Without the :: qualification, both the Bar::foo() declaration and the static_cast would fail because there is a user defined type Bar::foo that will be hit before the enum ::foo is found. Without the enum, the code will also fail to compile, as the global function ::foo() will be considered before the enum.

    Summing up, and after a long explanation: don’t. Avoid creating functions that have the same name that types, as that will most probably just cause confusion.


    [*] After rereading the standard, the C++ language does not define separate identifier spaces for user defined types. On the other hand, the rules in the standard are consistent with the description above. The main difference is that in C++ a typedef alias cannot be the same as any existing type other than the type it is aliasing:

    struct foo {};
    typedef int foo; // Error
    

    But for most other purposes, the behavior is consistent. There are a couple of corner cases that I did not mention in the body of the answer, but that are well beyond the scope of this question.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have tried the following code: $('a.buildMenu').click(function (event) { // Prevent normal behaviour event.preventDefault();
I have tried the following <input type=file name=upload multiple=multiple value=MyText> However the text on
I have tried the following code but has no effect: Imports system.Runtime.InteropServices <DllImport(UxTheme.DLL, BestFitMapping:=False,
I am currently working on Problem 62 I have tried the following code to
I have tried for unload and beforeunload binding in following code, but none of
Anything I have tried didn't work. Currenly I have following code to change asp.net
I have tried to use the following snippet of code: int main() { string
I've tried the following code with both normal ifstreams and the current boost:iostream I'm
The following code should show either the port or server name not both. I
I have the following code to call the onLoad and onBeforeUnload event: <script type=text/javascript>

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.