home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 31,894 of 33,346   
   =?ISO-8859-1?Q?Daniel_Kr=FCgler?= to TomaszMikolajczyk   
   Re: template class with non-type-param t   
   07 Feb 12 01:47:54   
   
   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)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca