#include <string>
#include <stdexcept>
#include <iostream>

template <class T>        
struct ConstrainedText {        
  std::string m;                 

protected:
  ConstrainedText() {}
  ~ConstrainedText() {}
public: 
  bool is_valid() {        
    return T::is_valid_string(m);        
  }        
        
  static T Create(std::string const & s)
  {
      if (T::is_valid_string(s)) {
          T t;
          static_cast<ConstrainedText<T>&>(t).m = s;
          return t;
      }

      throw std::runtime_error("invalid input!");
  }
};        
        
struct Angle : public ConstrainedText<Angle> {        
   static bool is_valid_string( std::string s ) {         
      return s == "deg" || s=="rad";        
   }          
};        
        
        
struct Length : public ConstrainedText<Length> {        
   static bool is_valid_string( std::string s ) {         
      return s == "mm" || s == "m" || s == "ft" || s == "in";        
   }          
};        

int main()
{
   auto a = Angle::Create("deg");
   auto l = Length::Create("mm");

   try {
       Angle::Create("bimbo");
   } catch (std::runtime_error & pEx) {
       std::cout << "exception as expected" << std::endl;
   }

   try {
       Length::Create("bimbo");
   } catch (std::runtime_error & pEx) {
       std::cout << "exception as expected" << std::endl;
   }
}