1

I need to write 2 constructors for a quaternion class that basically contains nothing but 4 elements of a numerical type T. I have 2 constructors in conflict at compile time (see below). Is it possible to tell the compiler to ignore the constructor from an iterator if I want to call the constructor that takes 4 ints (my attempt commented out - it seems the compiler sees my attempt as all or nothing to instantiate the whole class). The (clang) compiler complaint is "ambiguous conversion", and it lists these 2 constructors when trying to do Quaternion<float> x(1);

With my commented out attempt, clang tells me:

error: no type named 'value_type' in 'std::__1::iterator_traits<float>'
      typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>

The code:

template <typename T>
class Quaternion {
  public:
   template<typename T1>
   Quaternion(T1 a = 0, T1 b = 0, T1 c = 0, T1 d = 0)
   : _a(static_cast<T>(a)),
     _b(static_cast<T>(b)),
     _c(static_cast<T>(c)),
     _d(static_cast<T>(d)) { }

   template <typename It>
   //typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type>
   Quaternion(It it)
   : _a(static_cast<T>(++it)),
     _b(static_cast<T>(++it)),
     _c(static_cast<T>(++it)),
     _d(static_cast<T>(++it))
   {}

  private:
    T _a, _b, _c, _d;
};
Frank
  • 4,341
  • 8
  • 41
  • 57

1 Answers1

1

You could define a custom trait is_iterator:

template<typename T, typename = void>
struct is_iterator {
   static bool const value = false;
};

template<typename T>
struct is_iterator<T, typename std::enable_if<!std::is_same<typename std::iterator_traits<T>::value_type, void>::value>::type> {
   static bool const value = true;
};

And SFINAE out your constructors with a defaulted template argument in the following way:

template<typename T1, typename = typename std::enable_if<!is_iterator<T1>::value>::type>
Quaternion(T1 a = 0, T1 b = 0, T1 c = 0, T1 d = 0)
:_a(static_cast<T>(a)),
 _b(static_cast<T>(b)),
 _c(static_cast<T>(c)),
 _d(static_cast<T>(d)) 
 {}

template <typename It, typename = typename std::enable_if<is_iterator<It>::value>::type>
Quaternion(It it)
:_a(static_cast<T>(*(++it))),
 _b(static_cast<T>(*(++it))),
 _c(static_cast<T>(*(++it))),
 _d(static_cast<T>(*(++it)))
{}

Live Demo

101010
  • 41,839
  • 11
  • 94
  • 168