Literal ints are non-const?

This is a discussion on Literal ints are non-const? within the C++ Programming forums, part of the General Programming Boards category; Could someone please explain to me why a literal integer is an rvalue of type int instead of an rvalue ...

  1. #1
    C++ Junkie Mozza314's Avatar
    Join Date
    Jan 2011
    Location
    Australia
    Posts
    174

    Literal ints are non-const?

    Could someone please explain to me why a literal integer is an rvalue of type int instead of an rvalue of type const int?

    In particular, it creates this strange situation:

    Code:
    template <typename T>
    void foo(T&) { }
    
    int main()
    {
        foo(3); // error
        foo("asdf"); // ok
        return 0;
    }
    Error message:
    Code:
    literalIntTest.cpp: In function ‘int main()’:
    literalIntTest.cpp:6: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’
    literalIntTest.cpp:2: error: in passing argument 1 of ‘void foo(T&) [with T = int]’
    I realise that I can do:

    Code:
    template <typename T>
    void foo(const T&) { }
    But why aren't literals const?

    I suppose maybe this is a good thing though as it encourages const-qualification where possible in templates?
    Last edited by Mozza314; 11-08-2011 at 08:41 PM. Reason: Forgot to remove #include <iostream>

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,602
    Quote Originally Posted by Mozza314
    Could someone please explain to me why a literal integer is an rvalue of type int instead of an rvalue of type const int?

    In particular, it creates this strange situation:
    I do not find anything strange about foo(3) failing to compile, and I would expect pretty much the same error even if your compiler regarded 3 as a const int. What I do find strange is that foo("asdf") compiles, but as both g++ 4.4.5 and the Comeau online compiler accept it, I guess that it is correct (though I thought it was not allowed, in the previous version of C++... or maybe this is a quirk of template argument/parameter matching).

    Quote Originally Posted by Mozza314
    But why aren't literals const?
    Maybe because it does not really matter since they are "pure" rvalues anyway, and you cannot just take an address of an integer literal and attempt to modify the integer literal, whereas with a string literal's conversion to a pointer to its first element, attempts to modify a string literal's content should be guarded against, hence "asdf" is a const char[5].
    Last edited by laserlight; 11-08-2011 at 09:11 PM.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    C++ Junkie Mozza314's Avatar
    Join Date
    Jan 2011
    Location
    Australia
    Posts
    174
    Quote Originally Posted by laserlight View Post
    I would expect pretty much the same error even if your compiler regarded 3 as a const int.
    Why? If 3 was a const int then we would have [T = const int]:
    Code:
    void foo(const int&) { }
    Unless the compilation of this code is also strange to you:

    Code:
    void foo(const int&) { }
    
    int main()
    {
        foo(3);
        return 0;
    }

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    21,602
    Quote Originally Posted by Mozza314
    Why?
    Because I do not expect T = const int.

    Quote Originally Posted by Mozza314
    If 3 was a const int then we would have [T = const int]:
    That is what I think is kind of weird and potentially mistake prone: the template parameter T is not const qualified in the function's parameter list, but the template argument is const qualified, so although it looks like T objects would be modifiable lvalues, they aren't.

    Quote Originally Posted by Mozza314
    Unless the compilation of this code is also strange to you:
    It is clear that the parameter is a const lvalue reference, so there is no surprise that an rvalue temporary may be bound to it.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    C++ Junkie Mozza314's Avatar
    Join Date
    Jan 2011
    Location
    Australia
    Posts
    174
    Quote Originally Posted by laserlight View Post
    Because I do not expect T = const int.
    Ah! You're right!

    I can see it with this code:

    Code:
    template <typename T>
    void foo(T t) { t.Fail(); }
    
    int main()
    {
        const int x = 3;
        foo(x);
        return 0;
    }
    Code:
    constT.cpp: In function ‘void foo(T) [with T = int]’:
    constT.cpp:7:   instantiated from here
    constT.cpp:2: error: request for member ‘Fail’ in ‘t’, which is of non-class type ‘int’
    That seems really weird to me though. I'm used to thinking about 'const' as being part of the type, I mean you can do overloads based on constness and also typedefs:

    Code:
    template <typename T>
    void foo(T t) { t.Fail(); }
    
    typedef const int cint;
    
    int main()
    {
        cint x = 3;
        foo(x); // (only error in this program is the same one from here)
        return 0;
    }
    Naturally, I expected that the compiler would see a request for void foo(const int&) and match it using [T = const int].

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,299
    If T resolved to const-something, then how would you declare an instance of type (non const)-something inside that template function?
    i.e.
    Code:
    template <typename T>
    T foo(T &val) {
        T inOutParam = val; // Need this to be non-const
        fronbnicate(&inOutParam); // Takes a pointer to a non-const T
        return inOutParam;
    }
    The solution for C++ being that the template type does not include constness.
    Last edited by iMalc; 11-08-2011 at 11:36 PM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  7. #7
    C++ Junkie Mozza314's Avatar
    Join Date
    Jan 2011
    Location
    Australia
    Posts
    174
    Like this? You have to do this sort of thing with explicit templates anyway right?

    (EDIT: I can make this more clear by making Fronbnicate non-empty)

    Code:
    #include <iostream>
    
    template <typename T>
    struct RemoveConst
    {
        typedef T Type;
    };
    
    template <typename T>
    struct RemoveConst<const T>
    {
        typedef T Type;
    };
    
    template <typename T>
    typename RemoveConst<T>::Type Foo(T& val)
    {
        typename RemoveConst<T>::Type inOutParam = val;
        Fronbnicate(&inOutParam);
        return inOutParam;
    }
    
    template <typename T>
    void Fronbnicate(T* t) { --(*t); }
    
    int main()
    {
        std::cout << Foo<const int>(1000) << std::endl;
        return 0;
    }
    Output:

    Code:
    999
    Last edited by Mozza314; 11-08-2011 at 11:50 PM. Reason: Make it more clear.

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,299
    I think that further shows why things are as they are. A const const int wouldn't make sense, so on top of the language allowing the type T to contain const information if it did so, it would have to include rules about how to handle things that would resolve to double constness, and depending on what the language did there, you could end up with ambiguiuties.
    You would certainly agree that it's easier to add constness than to remove it.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    C++ Junkie Mozza314's Avatar
    Join Date
    Jan 2011
    Location
    Australia
    Posts
    174
    Yeah, I'm glad that I've got my head wrapped around implicit templates a bit more now.

    However, I'm fairly sure C++ does deal with const const int by collapsing it to const int. For example:

    Code:
    #include <iostream>
    
    template <typename T>
    void TypeTest(T t) { t.Fail(); }
    
    typedef const int cint;
    typedef const cint ccint;
    
    int main()
    {
        ccint x = 3;
        TypeTest<ccint>(x);
    
        return 0;
    }
    This code compiles ok if you omit line 12. However, by including it, g++ gives this error:

    Code:
    doubleConst.cpp: In function ‘void TypeTest(T) [with T = const int]’:
    doubleConst.cpp:12:   instantiated from here
    doubleConst.cpp:4: error: request for member ‘Fail’ in ‘t’, which is of non-class type ‘const int’
    So ccint, which was const (const int) resolves to const int.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. question about const pointers and const ints
    By WarDoGG in forum C Programming
    Replies: 9
    Last Post: 01-08-2011, 01:11 PM
  2. Replies: 3
    Last Post: 11-15-2009, 03:57 AM
  3. Replies: 1
    Last Post: 04-03-2009, 08:52 AM
  4. const references initialized to a literal
    By Mario F. in forum C++ Programming
    Replies: 3
    Last Post: 05-29-2006, 08:52 AM
  5. Enum or Const Ints?
    By Syneris in forum C++ Programming
    Replies: 5
    Last Post: 01-20-2006, 03:58 AM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21