d6236499   
   From: daniel.kruegler@googlemail.com   
      
   On 2012-02-07 00:59, TomaszMikolajczyk wrote:   
   > Recently I encountered the following problem:   
   >   
   > Consider a basic Range class encapsulating two values (possibly two   
   integers):   
   >   
   > template   
   > class Range   
   > {   
   > public:   
   > /// PRECONDITION: min<= max.   
   > Range(const T& min, const T& max) : _min(min), _max(max)   
   > {   
   > assert(min<= max);   
   > }   
   > const T& getMin() const { return _min; }   
   > const T& getMax() const { return _max; }   
   > private:   
   > T _min, _max;   
   > };   
   >   
   > Object creation example:   
   > auto r = Range(1, 2);   
      
   Just a first impression here: I really would encourage you to provide a   
    factory function for automatic deduction of the underlying type of the   
   range, e.g.   
      
   template   
   Range make_range(const T& min, const T& max)   
   {   
    return Range(min, max);   
   }   
      
   > Improving the interface I would like to have a possibility to provide   
   > the min-max range statically, that is at compile time.   
      
   Am I right that the reason for providing these values statically is to   
   allow for static validation of the relative sizes?   
      
   > To do that I defined   
   > a template constructor with two non-type template params:   
   >   
   > template   
   > class Range   
   > {   
   > public:   
   > /// PRECONDITION: min<= max.   
   > Range(const T& min, const T& max) : _min(min), _max(max)   
   > {   
   > assert(min<= max);   
   > }   
   >   
   > template   
   > Range() : _min(min), _max(max)   
   > {   
   > static_assert(min<= max, "invalid range");   
   > }   
   >   
   > const T& getMin() const { return _min; }   
   > const T& getMax() const { return _max; }   
   > private:   
   > T _min, _max;   
   > };   
   >   
   > The problem is that I don't have idea how to create an object of the   
   > Range class using such template constructor. Does the standard allows   
   > for such definition?   
      
   No, because there is no deduction or explicit template parameter   
   provision possible here.   
      
   What about   
      
   template   
   Range make_range()   
   {   
    static_assert(Min <= Max, "invalid range");   
    return Range(Min, Max);   
   }   
      
   which would be used like this:   
      
   auto r = make_range();   
      
   ?   
      
   > I can achieve such thing in the following ways:   
   > 1) Static "make_range" method, or   
   > 2) Nested template class   
   >   
   > template   
   > class Range   
   > {   
   > public:   
   > Range(const T& min, const T& max) : _min(min), _max(max)   
   > {   
   > assert(min<= max);   
   > }   
   >   
   > template   
   > Range() : _min(min), _max(max)   
   > {   
   > static_assert(min<= max, "invalid range");   
   > }   
   >   
   > const T& getMin() const { return _min; }   
   > const T& getMax() const { return _max; }   
   >   
   > /// solution #1   
   > template   
   > static Range make_range()   
   > {   
   > static_assert(min<= max, "invalid range");   
   > return Range(min, max);   
   > }   
   >   
   > /// solution #2   
   > template   
   > class StaticRange : private Range   
   > {   
   > public:   
   > StaticRange() : Range(min, max)   
   > {   
   > static_assert(min<= max, "invalid range");   
   > }   
   > using Range::getMin;   
   > using Range::getMax;   
   > };   
   >   
   > private:   
   > T _min, _max;   
   > };   
   >   
   > Ad 1. Static "make_range" method:   
   >   
   > Example usage:   
   > auto r = Range::make_range<1, 2>();   
   >   
   > Disadvantage: class CopyConstructible requirement.   
      
   I don't understand your rationale. Which type needs to satisfy the   
   CopyConstructible requirements? From your original Range template we can   
   already deduce that you need to impose the CopyConstructible   
   requirements on T (assuming T is an object type). Without this   
   requirement you could not construct your _min and _max members anyway.   
      
   As an example try this:   
      
   struct NoCopy {   
    int n;   
    NoCopy(int n) : n(n) {}   
    NoCopy(const NoCopy&) = delete;   
    friend bool operator<=(const NoCopy& n1, const NoCopy& n2) { n1.n <=   
   n2.n; }   
   };   
      
   NoCopy m1(-1);   
   NoCopy p1(+1);   
      
   Range r(m1, p1);   
      
   Therefore: The function make_range does not make the situation worse, it   
   just imposes the same requirements as any other instantiation of   
   template Range.   
      
   Personally I don't see a reason to make this make_range function a   
   static member function instead of a free function template as shown above.   
      
   > Ad. 2. Nested template class:   
   >   
   > Example usage:   
   > auto r = Range::StaticRange<1, 2>();   
   >   
   > The advantage over the solution #1 is that class CopyConstructible   
   > requirement does not apply.   
      
   I don't see how you came to that conclusion. Both T and Range (by   
   implication) have to satisfy the CopyConstructible requirements. The   
   constructor of StaticRange has to copy the values into the base class.   
      
   > The disadvantage is that it constructs   
   > a separate type, that is StaticRange instead of Range.   
      
   Yes, I don't see any good reason for StaticRange.   
      
   > Summarizing the problem: how to construct object of class Range   
   > with the following constructor's declaration:   
   >   
   > template   
   > class Range   
   > {   
   > public:   
   > template   
   > Range();   
   > };   
      
   This requirement cannot be solved as written. The template constructor   
   can never be invoked.   
      
   HTH & Greetings from Bremen,   
      
   Daniel Krügler   
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|