Thread: strange #define problem

  1. #1
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445

    strange #define problem

    I am using G++ 4.5 on OpenSUSE 11.3, and I have a macro defined as follows:

    Code:
    template<class destT>
    destT GetSiteSetting(client& cli, const destT&, const std::string& name)
    {
      try
      {
        return boost::lexical_cast<destT>(cli.GetSiteRef()[name]);
      }
      catch (boost::bad_lexical_cast& ex)
      {
        return destT();
      }
    }
    
    #define GET_SITE_SETTING(TYPE, NAME) TYPE NAME = GetSiteSetting(cli, TYPE(), #NAME)
    it is specifically intended to be used inside a function in which a client object called cli is accepted as a parameter.

    the trouble comes in when the type I use contains spaces, such as "unsigned long"

    even when I do a typedef as follows:

    Code:
    typedef long long LONG;
    and then try to use the macro like so:

    Code:
    GET_SITE_SETTING(LONG, foo);
    is C++ supposed to produce this sort of behavior? I would expect that the compiler would recognize the first parameter as a valid type name, regardless of the fact that it contains spaces. I realize that G++ defines things like int64_t, but not all compilers do, and I'd like to keep it portable.

  2. #2
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    I suppose it would help if I explained what type of behavior I was seeing.

    when I use a data type containing spaces, such as unsigned long, I get the following error:

    Code:
    error: expected primary-expression before 'long'

  3. #3
    Registered User
    Join Date
    Feb 2006
    Posts
    312
    I honestly can't explain what's going on with the preprocessor there, but it seems that the problem also occurs on comeau tryitout too. However, I wonder if this would be suitable as a workaround
    Code:
    template <typename destT>
    struct type_wrapper
    {
        typedef destT type;
    };
    
    template<class destT>
    typename destT::type GetSiteSetting(client& cli, const destT&, const std::string& name)
    {
      try
      {
        return boost::lexical_cast<typename destT::type>(cli.GetSiteRef()[name]);
      }
      catch (boost::bad_lexical_cast& ex)
      {
        return typename destT::type();
      }
    }
    
    #define GET_SITE_SETTING(TYPE, NAME) TYPE NAME = GetSiteSetting(cli, type_wrapper<TYPE>(), #NAME)
    By wrapping your unsigned long into type_wrapper<>, you are avoiding the issue with having a type containing the qualifier. I can't quite see what the preprocessor doesn't like about them however. (But I do trust comeau to have implemented it correctly; no doubt there is some subtle parsing rule in the C or C++ standards responsible here)


    edit - I didn't check the above code in comeau, since it doesn't know about boost::lexical_cast, however I did test this code in comeau and it seemed happy
    Code:
    #include <string> 
    
    template <typename destT>
    struct type_wrapper
    {
        typedef destT type;
    };
    
    template<class destT>
    typename destT::type GetSiteSetting(const destT&, const std::string& name)
    {
    
        return (typename destT::type());
    }
    
    #define GET_SITE_SETTING(TYPE, NAME) TYPE NAME = GetSiteSetting(type_wrapper<TYPE>(), #NAME)
    
    int main()
    {
        GET_SITE_SETTING(unsigned long, foo);
    }
    Last edited by Bench82; 07-08-2011 at 03:48 PM.

  4. #4
    Registered User
    Join Date
    Feb 2006
    Posts
    312
    ah, it seems to be nothing at all related to the preprocessor, it seems to be related to initialising data types with a qualifier inside a function's argument list
    Code:
    void foo(const unsigned long&, const char*)
    {
    }
    
    int main()
    {
        foo(unsigned long(), "hello");  // Comeau says "Error!"
    }
    Is there anybody more familiar with the standard than me who might recognise the parsing rule which causes the above code to throw out an error about the unsigned qualifier?

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Is there a reason you need a macro instead of a template function?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    I'm not sure offhand about all the details, but seem to recall the offending rule concerns primary expressions (a primary expression is a literal, a name, and a couple of other things). A name can only be one token, and a qualified type name is seen by the parser as two, so unsigned long() is not deemed a primary expression, but long() is.

    Personally, I've always viewed this sort of thing as an anomaly.

    The easiest (although not particularly satisfying) workaround I can think of is to beat the compiler into submission. Use default arguments in your template function definition, swap the order of arguments so the offending argument is last in the list, and use an explicit instantiation in your macro.
    Code:
        template<class destT>
            destT GetSiteSetting(client& cli, const std::string& name, const destT& = destT())
    {
        // etc
    }
    
    #define GET_SITE_SETTING(TYPE, NAME) TYPE NAME = GetSiteSetting<TYPE>(cli, #NAME)
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  7. #7
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    Quote Originally Posted by Elysia View Post
    Is there a reason you need a macro instead of a template function?
    the same reason anyone would use a macro: to reduce the amount of code that I have to write. in this case, it retains clarity, and in far fewer keystrokes, serves as the declaration and assignment of a variable, while using the template function behind the scenes.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I don't see the need for a macro over a template function to achieve your goal, however:
    auto FooSetting = GetSiteSetting<unsigned long>(cli, "foo");
    Not too horrible and avoids macros.
    And it avoids implicitly declaring a variable.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    I agree with you regarding the idea of an implicitly declared variable, but because I'm the only one maintaining this code, the meaning is not obscured significantly by the macro, and given the overall size of the project (200k+ lines), a 50% savings of keystrokes is worth a possible slight degradation in code readability, in my opinion. in other situations it wouldn't be appropriate, but I see this as an acceptable compromise.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I would disagree, but if your mind is made up, there is little I can do to change it.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. #define problem in C
    By chandanpatra in forum C Programming
    Replies: 1
    Last Post: 03-07-2011, 04:31 AM
  2. #define problem
    By reaperman in forum C++ Programming
    Replies: 7
    Last Post: 10-27-2008, 06:48 PM
  3. a #define problem
    By spank in forum C Programming
    Replies: 5
    Last Post: 01-24-2006, 06:19 AM
  4. Some weird #define problem
    By johny145 in forum Windows Programming
    Replies: 1
    Last Post: 07-31-2005, 10:12 AM
  5. struct and define problem
    By hurry up in forum C Programming
    Replies: 1
    Last Post: 03-19-2003, 11:37 AM