Search code examples
c++templatesconditional-compilation

Conditional code depending on template parameters comparision


everybody! Want to make method compiling differently depending on template parameters.

template <unsigned long prec> class DFixed {
public:
  unsigned long val;
...
  template <unsigned long prec1> DFixed<prec> &operator-=(DFixed<prec1> d) {
    #if prec==prec1
    val -= d.val;
    #elif prec<prec1
    val -= d.val/(prec1/prec);
    #else
    val -= d.val*(prec/prec1);
    #endif
    return *this;
  }
...
};

But the code above calls block for prec==prec1 even for different precs.


Solution

  • As already said, C++17's if constexpr is the best solution:

    template <unsigned long prec1>
    DFixed & operator-=(DFixed<prec1> d) {
        if constexpr (prec==prec1)
            val -= d.val;
        else if constexpr (prec<prec1)
            val -= d.val/(prec1/prec);
        else
            val -= d.val*(prec/prec1);
    
        return *this;
    }
    

    If you're using C++11, you can use SFINAE with std::enable_if hidden in a REQUIRES macro:

    #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__), int>::type = 0
    
    template <unsigned long prec1, REQUIRES(prec==prec1)>
    DFixed & operator-=(DFixed<prec1> const & d) {
        val -= d.val;
        return *this;
    }
    template <unsigned long prec1, REQUIRES(prec<prec1)>
    DFixed & operator-=(DFixed<prec1> const & d) {
        val -= d.val/(prec1/prec);
        return *this;
    }
    template <unsigned long prec1, REQUIRES(prec>prec1)>
    DFixed & operator-=(DFixed<prec1> const & d) {
        val -= d.val*(prec/prec1);
        return *this;
    }
    

    Note that input parameter d is passed by const reference to avoid unnecessary copy.