c++templates

Compiler cannot deduce the specialised template in C++


I have the following code in a class

  struct ConstrType{};
  struct ConstrType3{};
  struct ConstrType2{};
  struct ConstrType1{};

  template<typename InType, typename OutType, typename ConstrType>
  class getInterestRateIndex_impl{
  public:
    getInterestRateIndex_impl(){
      std::cout << "Generic getInterestedRateIndex_impl instantiated. Failed" << std::endl;
//      BOOST_STATIC_ASSERT(sizeof(ConstrType) == 0);
    }
    boost::shared_ptr<OutType> operator()() const{
      return boost::shared_ptr<OutType>();
    }
  };


  template<typename InType, typename OutType>
  class getInterestRateIndex_impl<InType, OutType, ConstrType2>{
  public:
    getInterestRateIndex_impl(){
      std::cout << "ConstrType2 getInterestedRateIndex_impl instantiated." << std::endl;
    }
    boost::shared_ptr<OutType> operator()() const{
      return boost::shared_ptr<OutType>();
    }
  };


  template<typename InType, typename OutType>
  class getInterestRateIndex_impl<InType, OutType, ConstrType1>{
  public:
    getInterestRateIndex_impl(){
      std::cout << "ConstrType1 getInterestedRateIndex_impl instantiated." << std::endl;
    }
    boost::shared_ptr<OutType> operator()() const{
      return boost::shared_ptr<OutType>();
    }
  };



  template<typename InType, typename OutType>
  boost::shared_ptr<OutType> getInterestRateIndex() const{
//    BOOST_STATIC_ASSERT(boost::is_base_of<OutType, InType>::value);

    typedef typename
      boost::mpl::if_
      <
          boost::is_same<InType, QuantLib::Libor>,
          QuantLib::Libor,
          boost::mpl::if_
          <
              boost::mpl::or_
              <
                  boost::mpl::or_
                  <
                      boost::is_same<InType, QuantLib::Euribor>,
                      boost::is_same<InType, QuantLib::EURLibor>,
                      boost::is_base_of<QuantLib::Libor, InType>
                  >
              >,
              ConstrType2,
              boost::mpl::if_
              <
                  boost::mpl::or_
                  <
                      boost::is_base_of<QuantLib::Euribor, InType>,
                      boost::is_base_of<QuantLib::EURLibor, InType>
                  >,
                  ConstrType1,
                  ConstrType
              > 
          > 
      >::type Type;
//    std::cout << typeid(Type).name() << std::endl;
//    throw std::exception(typeid(Type).name());

    return getInterestRateIndex_impl<InType, OutType, Type>()( );

  }

When I instantiate the class and invoke getInterestRateIndex<DerivedFromLiborType, BaseType>(), the compiler cannot choose the specialisation. When I uncomment the exception line, it can though detect that the Type after typedef is ConstrType2. Am I missing anything that can hint the compiler to choose the right specialisation?

PS: the template logic suppose to do something like .....

if(T is Libor)
    return LiborType
if(
   or(
      or(T = Euribor,
         T = EURLibor),
      is_base_of(T, Libor)
    ),
    ConstrType2,
    if( 
        or(is_base_of(T, Euribor),
           is_base_of(T, EURLibor)),
       ConstrType1,
       ConstrType
      )
   )

I do this because I need to dispatch shared_ptr based on the input type, and the desired underlying type in the shared_ptr wrapper.


Solution

  • The problem is that the outer if statement cannot deduce the type of the "then" branch and return a compounded type of boost structs and therefore always choosing the full unspecialised template