当错误的类型(double)传递给它而不是std :: complex时,std :: enable_if无法动作

时间:2016-10-11 15:57:20

标签: c++ c++11 templates sfinae complex-numbers

我希望我的数组类将数据从double数组复制到std::complex<double>(或任何U到std :: complex)数组,并使用operator=。为此,我使用了std::enable_if。但是,它未能检测到它不应该被使用。

以下函数,如果类型T复杂,我想调用它。所以我使用条件std::is_same<T, std::complex<typename T::value_type>,因为std::complex存储了它在::value_type中使用的类型。这是函数的定义:

template <typename T, int S>
typename std::enable_if<std::is_same<T, std::complex<typename T::value_type> >::value, MyArray<T,S>& >::type
MyArray<T,S>::operator=(const typename std::enable_if<std::is_scalar<typename T::value_type>::value, MyArray<typename T::value_type>&, S >::type rhs)

但是,如果我尝试复制MyArray<double>,则会出现以下错误。显然,它没有发现double不是“

  

错误:'double'不是类,结构或联合类型    MyArray :: operator =(const typename std :: enable_if :: value,MyArray&amp;,S&gt; :: type rhs)

我在这里做错了什么?

更新

我想让我想做的事情变得清晰,因为(抱歉)有太多混乱。

我需要这个操作:

MyArray<double> d;
MyArray<std::complex<double>> cd;
cd = d;

2 个答案:

答案 0 :(得分:3)

不确定但是......如果您希望仅在传入的operator=()MyArray<T> T合并std::complex<U>时才启用 template <typename F> MyArray & operator= (MyArray<std::complex<F>> const & rhs) { return *this } ,为什么不要&#39}你简单地写一下

U

<强> - 编辑 -

  

我想将std::complex<U>分配给MyArray<std::complex<U>> = MyArray<U>,所以#include <complex> #include <type_traits> template <typename T> struct MyArray { template <typename U> typename std::enable_if<std::is_same<T, std::complex<U>>::value, MyArray &>::type operator= (MyArray<U> const & rhs) { return *this; } }; int main() { MyArray<double> d; MyArray<std::complex<double>> cd; cd = d; }

所以你想要完全相反。

我想你可以做点什么

#include <complex>
#include <type_traits>

template <typename T, int S>
struct MyArray
 {
   template <typename U>
   typename std::enable_if<std::is_same<T, std::complex<U>>::value,
        MyArray &>::type 
    operator= (MyArray<U, S> const & rhs)
     { return *this; }
 };

int main()
 {
   MyArray<double, 3> d;
   MyArray<std::complex<double>, 3> cd;
   cd = d;
 }

- 编辑2 -

  

但是我在原始问题中删除了第二个模板参数,认为我简化了可读性问题。但是我这样做是错误的,因为在C ++中不允许对函数进行部分特化。所以我的模板是模板,而不是模板,这是非常不同的

我认为这不是必要的部分专业化

operator()

如果问题在于定义班级正文之外的#include <complex> #include <type_traits> template <typename T, int S> struct MyArray { template <typename U> typename std::enable_if<std::is_same<T, std::complex<U>>::value, MyArray &>::type operator= (MyArray<U, S> const & rhs); }; template <typename T, int S> template <typename U> typename std::enable_if<std::is_same<T, std::complex<U>>::value, MyArray<T, S> &>::type MyArray<T, S>::operator= (MyArray<U, S> const & rhs) { return *this; } int main() { MyArray<double, 3> d; MyArray<std::complex<double>, 3> cd; cd = d; } ,我建议以下修改后的例子

#include <complex>
#include <type_traits>

template <typename T, int S>
struct MyArray
 {
   template <typename U>
   typename std::enable_if<std::is_same<T, std::complex<U>>::value,
         MyArray &>::type 
      operator= (MyArray<U, S> const & rhs)
       { return *this; }

   template <typename U,
            typename = typename std::enable_if<std::is_same<T,
                           std::complex<U>>::value>::type>
   MyArray (MyArray<U, S> const & rhs)
    { }

   MyArray() = default;
   MyArray(MyArray const &) = default;
   MyArray(MyArray &&) = default;
   ~MyArray() = default;
 };

int main()
 {
   MyArray<double, 3> d;                      // need MyArray() = default
   MyArray<double, 3> d2(d);                  // OK
   MyArray<float, 3> f;                       // OK
   MyArray<std::complex<double>, 3> cd(d);    // OK
   //MyArray<std::complex<double>, 3> cd2(f); // error!
   cd = d;

 }

- 编辑3 -

  

有没有办法对拷贝构造函数做同样的事情? [...]这很棘手,似乎不可能,因为没有返回类型。

是的,有办法

= default

观察boolean个添加的行;没有第一个(我不知道其他三个是否有用)代码没有编译,因为(如果我理解正确)SFINAE复制构造函数禁用(删除)默认复制构造函数所以删除其他默认构造函数和默认析构函数。

答案 1 :(得分:1)

在尝试理解模板问题时,我发现有些帮助,请自行尝试替换:

template <double>
typename std::enable_if<std::is_same<double, std::complex<typename double::value_type> >::value, MyArray<double>& >::type
MyArray<double>::operator=(const typename std::enable_if<std::is_scalar<typename double::value_type>::value, MyArray<typename double::value_type>& >::type rhs)

现在很明显吗?如果doubleMyArray类型T,那么T将在上面的SFINAE逻辑中使用。但double没有::value_type

您可以尝试这样的事情:

template<typename T>
typename std::enable_if<std::is_scalar<T>, MyArray<T>&>::type
  MyArray<T>::operator=(const std::complex<T>& rhs){...}

如果您不需要is_scalar检查,请改用max66的答案。

<强>更新
奥基-dokey。因此,此 地址希望通过赋值运算符从MyArray<T>转到MyArray<std::complex<T>>,而不是相反。

template<typename T, typename U>
typename std::enable_if<std::is_same<T, std::complex<U>>::value && std::is_scalar<U>::value, MyArray<T>&>::type
  MyArray<T>::operator=(const MyArray<U>& rhs){...}

这里的诀窍是intstd::complex<int>不是同一类型。您也可以将T::value_type替换为U来完成此操作。最后,您可以通过对MyArray<T>类进行部分专业化来实现它,以便MyArray<std::complex<T>>类,如果您发现自己需要更多类似于您所要求的内容,则可能值得考虑。