2
//THIS IS JUST A FRAGMENT OF A static_numeric_limits.h for the purpose of this example   
 #include <limits.h>

    template<class T>
    struct static_numeric_limits;

    template<>
    struct static_numeric_limits<signed char>
    {/*min was outside of range for enum*/
        static const signed char min = SCHAR_MIN,
                                 max = SCHAR_MAX;
    };

    /*This "surplus" template is here for the reason that char is threated differently from signed char */
    template<>
    struct static_numeric_limits<char>
    {/*min was outside of range for enum*/
        static const char min = SCHAR_MIN,
                          max = SCHAR_MAX;
    };

    template<>
    struct static_numeric_limits<unsigned char>
    {
        static const unsigned char min = 0x0,
                             max = UCHAR_MAX;
    };
 ///REAL PROBLEM STARTS FROM HERE      
     template<class IntType,IntType low_range = static_numeric_limits<IntType>::min>
    struct Int
    {
        Int():value_(IntType())
        {}
        Int(const IntType& pattern)
        {
            value_ = (pattern);
        }
        constexpr inline IntType getValue()const
        {
            return value_;
        }
    private:
        IntType value_;
    };

    template<class IntType,class IntType_1>
    auto operator+
        (Int<IntType>& lhs, Int<IntType_1>& rhs)
        -> Int<decltype(lhs.getValue() + rhs.getValue())>//HERE IS THE PROBLEM
    {
        return lhs.getValue() + rhs.getValue();
    }

Error (from VS2010) error C2027: use of undefined type 'static_numeric_limits<T>'
Error (from gcc 4.6)
error: 'decltype ((lhs->getValue() + rhs->getValue()))' is not a valid type for a template constant parameter

Why doesn't this work as I thought it would?

GManNickG
  • 494,350
  • 52
  • 494
  • 543
There is nothing we can do
  • 23,727
  • 30
  • 106
  • 194
  • Note that for `getValue` to be marked as `constexpr`, your constructor needs to be marked `constexpr`, so that there's a way for `value_` to be a constant expression. – GManNickG May 10 '11 at 00:22

1 Answers1

1

The error here is what type decltype is deducing from your expression; unfortunately the error messages aren't clear about it, and it's actually a bit of a tricky problem.

Consider the type of the expression 0 + 0. It's an int, yes, but more importantly it's an rvalue (informally, it's a temporary). This means that decltype(0 + 0) is not int, but int&&. Now consider that your code isn't any different, in this regard: you still have an rvalue.

The problem is that template non-type parameters cannot be rvalue references, so you cannot have Int<int&&>, because of the second parameter's type . What you can do, though is this:

#include <type_traits>

// ...

template <class IntType, class IntType_1>
auto operator+(const Int<IntType>& lhs, // be const-correct!
                const Int<IntType_1>& rhs)
                -> Int<typename std::remove_reference<
                        decltype(lhs.getValue() + rhs.getValue())>::type>
{
    return lhs.getValue() + rhs.getValue();
}

This takes the reference off int&&, giving you the bare int type. Hopefully gcc's error message makes a bit more sense: it's trying to tell you that you can't use int&& for your non-type parameter.


Another problem, though probably a non-issue, is that integer arithmetic undergoes what's called the usual arithmetic conversions. So the result of adding the values of two Int<char>'s is actually going to be an int, so your return type should be Int<int> (and is, with the fixed code).

The problem, then, is that you haven't defined static_numeric_limits<int>. But like I said, I suspect this is a non-issue and you do actually have it defined, just not displayed in your question.

Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • @GMan that is fantastic answer. Thanks. Would you know why those downvotes? What's wrong with this question? – There is nothing we can do May 04 '11 at 06:24
  • @There: There was a large discussion, but it was deleted. People felt you posted a rant and not a question, because of your statement at the end, and so closed it and down-voted it. I argued that wasn't the case, clarified with an edit, and suggested people only decided to see it as a rant because they don't like your other questions. Regardless of who was right, the question was reopened and the comments were deleted. In the future, though, try to make your question as clear as possible and try to trim off any thoughts or frustration you have. – GManNickG May 04 '11 at 06:37
  • @GMan I'm sorry but which part of my post indicated a rant? And for the love of God can't one express one's personal opinion? In what way did I insult or upset anyone? It's ridiciulous. – There is nothing we can do May 04 '11 at 07:09
  • @There: The last part where you said you feel like decltype might be useless. Yes, you can voice your opinion, but this is a Q&A site, not a blog, and it's best if you left those at the door. Keep in mind, like it or not, some people feel you have less leeway when it comes to off-topic stuff, since they feel your past questions tend to be not worth their time. Unfortunately, even if they're wrong that's still how it is, and it's probably in your best interest to just try to ask questions only, so you can show people you do actually want help and don't want to just rant, for clarity. – GManNickG May 04 '11 at 07:12
  • @GMan fair enough, can understand it, but if those people would read carefully my previous questions then they would realize that I never rant about C++. Java? sure, MJ? sure, but C++ never. Anyway, once again for your answer, it helps me immensly. – There is nothing we can do May 04 '11 at 09:14
  • @GMan unfortunately your solution seems to not working (just now had time to try it), did you try to compile it for yourself? Small update, it seems to work on gcc 4.6 but not on VS2010 sp1 – There is nothing we can do May 04 '11 at 11:40
  • @Theere: I tried it on gcc and it worked, let me see why VS is choking on it. – GManNickG May 04 '11 at 19:45
  • @There: Looks like yet another bug in the awful compiler we get from Microsoft. If I add a dummy constant to the base case of `static_numeric_limits`, it works, ala: `template struct static_numeric_limits { static const int min = 0; };`. – GManNickG May 04 '11 at 20:15
  • 1
    @GMan it will compile but you will get incorrect results at the end. I'm sorry (ok downvoters here we go) but Very Slow 2010 is so buggy that it is practically imposibble to do real work with it (using C++0x). Every possible feature from C++ is buggy in this compiler. Pathetic. – There is nothing we can do May 05 '11 at 06:17
  • 2
    Just because "0 + 0" yields an rvalue doesn't mean decltype(0 + 0) is int&&, as the [xvalue vs prvalue distinction matters](http://stackoverflow.com/q/5924870/511601). – Fred Nurk May 08 '11 at 03:09
  • @Fred: Sorry for the slow response. Forgive my ignorance, but is the reasoning behind the answer (ignoring the incorrect example) still right? – GManNickG May 10 '11 at 00:29
  • @GMan: Not according to the 0x FDIS, to the best of my current understanding. Your change is to add remove_reference, but I can't see why it would be required in the first place. – Fred Nurk May 10 '11 at 08:46
  • @GMan: Maybe the root cause is tied up in the constexpr you mentioned in a comment on the question. In any case, looking at this poster's code and questions always gives me a headache, so I try not to. – Fred Nurk May 10 '11 at 08:48