views:

236

answers:

3

I've been trying to make a generic class to represent a range of values but am having some difficulty trying to work out what I'm missing (the compiler comlplains about a missing copy constructor, but all the implementations I've tried have failed). So my questions:

  1. Is there a Range template somewhere I've missed to avoid me reinventing this wheel?
  2. What format does the copy constructor need to be in?
  3. Is there anything else I've missed?

Here's my code as it stands:

namespace MyNamespace {
    generic<typename T> public ref class Range
    {
    protected:
        T m_min;
        T m_max;
    public:
        Range(T min, T max)
        {
            m_min = min;
            m_max = max;
        }
        property T Min {
            T get() { return m_min; }
            void set(T min) { m_min = min; }
        }
        property T Max {
            T get() { return m_max; }
            void set(T max) { m_max = max; }
        }
    };

    public ref class MyClass
    {
    protected:
        Range<int> m_myRange;

    public:
        property Range<int> MyRange 
        {
            Range<int> get() { return m_myRange; }
            void set( Range<int> myRange ) { m_myRange = myRange; }
        }
    }
}

The compiler complains about copy constructors in the Range class:

1>c:\projects\collections\Range.h(71) : error C2440: 'return' : cannot convert from 'MyNamespace::Range<T>' to 'ZephIRControlsLib::Range<T>'
1>        with
1>        [
1>            T=int
1>        ]
1>        Cannot copy construct class 'MyNamespace::Range<T>' due to ambiguous copy constructors or no available copy constructor
1>        with
1>        [
1>            T=int
1>        ]
1>c:\projects\collections\Range.h(72) : error C2582: 'operator =' function is unavailable in 'MyNamespace::Range<T>'
1>        with
1>        [
1>            T=int
1>        ]
1>.\Range.cpp(8) : error C2512: 'MyNamespace::Range<T>' : no appropriate default constructor available
1>        with
1>        [
1>            T=int
1>        ]
+1  A: 

Why do you need a range of values?

What about using Boost.Range to represent a range within a collection? If you're interested in the min and max only, think std::numeric_limits.

Edouard A.
I have a user control which allows you to highlight a portion of data between two values. So it made sense to pass those values in as a single entitity (I'm only ever going to change them both at the same time). I'd like to keep the solution as .net-ish as possilbe so using boost is something I'd like to avoid if possible
Jon Cage
What about std::pair...
Edouard A.
Not a bad option, but two problems with that: [1] It's less obvious which value is the max and which is the min, and [2] I get problems when trying to add 'std::pair<int,int> test;' to my class - the compiler says 'error C4368: cannot define 'test' as a member of managed 'MyNamespace::MyClass': mixed types are not supported'?
Jon Cage
+1  A: 

I worked out the missing pieces which seem to work:

namespace MyNamespace {
    generic<typename T> public ref class Range
    {
    protected:
        T m_min;
        T m_max;
    public:
        Range()
        {
        }
        Range(T min, T max)
        {
            m_min = min;
            m_max = max;
        }
        Range(Range<RangeType>% rhs)
        {
            m_min = rhs.m_min;
            m_max = rhs.m_max;
        }
        Range% operator=(Range<RangeType>% rhs) 
        {
            m_min = rhs.m_min;
            m_max = rhs.m_max;
            return *this;
        }
        property T Min {
            T get() { return m_min; }
            void set(T min) { m_min = min; }
        }
        property T Max {
            T get() { return m_max; }
            void set(T max) { m_max = max; }
        }
    };

    public ref class MyClass
    {
    protected:
        Range<int> m_myRange;

    public:
        property Range<int> MyRange 
        {
            Range<int> get() { return m_myRange; }
            void set( Range<int> myRange ) { m_myRange = myRange; }
        }
    }
}
Jon Cage
+1  A: 

Kill the over engineering and make this a templated struct with 2 public members, min and max. It'll be tons easier to read and you won't have to write a bunch of unit tests for something you can just set directly.

Also seriously consider using the STL paradigm of a half open interval with "begin" and "end". This will actually help range merging make some logical sense for floating point when the ranges are adjacent.

Brian
I must admit, it felt like a rather large solution for something relatively simple. I've been trying to get my head around .net though recently. Do you have any examples or further information on the STL paradigm you mention?
Jon Cage
I tried using a struct, but that seems to incur the same problems - I think the .net elements of this are causing the problems; everything I've tried results in the compiler complaining about mixing types in the case of STL solutions or missing constructors etc. if I try to make a 'generic' struct.
Jon Cage