如果SFINAE启用了升压功能

时间:2014-10-10 14:23:04

标签: c++ templates boost sfinae enable-if

我正在尝试实现一个模板化的对类,它使用sfinae来区分数组和非数组类型。到目前为止,我有以下代码:

template <typename T>
class pair
{
public:

   //default constructors. one for non-array types and one for arrays. These work.
   template <typename temp_type = T>
   pair(typename boost::disable_if<boost::is_array<temp_type>>::type* ignore = 0)
      : first(T())
      , second(T())
   {}

   template <typename temp_type = T>
   pair(typename boost::enable_if<boost::is_array<temp_type>>::type* ignore = 0)
   {}

   //assignment operator attempts for non-array types (not in code at same time.) These don't work.
   template<typename temp_type = T> 
   pair<temp_type>& operator=(pair<typename boost::disable_if<boost::is_array<temp_type>>::type>                const& rhs)
   {
       this->first = rhs.first;
       this->second = rhs.second;
       return *this;
   }

   template<typename temp_type = T> 
   auto operator=(pair<temp_type> const& rhs) -> pair<typename boost::disable_if<boost::is_array<temp_type>>::type>&
   {
       this->first = rhs.first;
       this->second = rhs.second;
       return *this;
   }

   T first;
   T second;
};

对赋值运算符的第一次尝试失败,出现“非法使用类型void”错误。第二个编译,但是当我调试时,MSVC告诉我“没有可执行代码与该行相关联。”我正在使用MSVC 12 64位编译器。

如果你能提供任何关于这里有什么问题的见解,那将非常有帮助。

另外,我在c ++中对sfinae做了一些观察(可能是对还是错):

  • sfinae要求成员函数是模板化的,但它不能使用类模板类型来实现此目的。为什么?
  • sfinae只能通过修改模板参数而不是返回类型或输入来完成。这究竟是如何工作的。这种方法的灵活性是什么?

我知道这篇文章篇幅很长,很多其他帖子都提到了参考主题,但是我无法将这些解释放在一起,以简洁的方式解释c ++中的sfinae。

我读过的一些帖子:

Explain C++ SFINAE to a non-C++ programmer(高级别介绍)

Select class constructor using enable_if(构造函数的sfinae)

感谢您的帮助。

编辑:

我已经根据下面的评论修改了我的代码,但我仍然无法按预期工作(编译器甚至没有看到源代码。)这是一个有趣的情况因为这个例子完全是人为的并且默认赋值运算符实际上适用于此场景。不过,我认为编译器不应该覆盖我重载运算符的尝试。

我尝试了以下4种方法,但似乎没有内置于可执行文件中:

template<typename temp_type = T> 
pair<temp_type>& operator=(pair<typename boost::disable_if<boost::is_array<temp_type>, temp_type>::type> const& rhs)

{
        this->first = rhs.first;
        this->second = rhs.second;
        return *this;
}

template<typename temp_type = T>
auto operator=(pair<temp_type> const& rhs) -> pair<typename boost::disable_if<boost::is_array<temp_type>, temp_type>::type>&
{
    this->first = rhs.first;
    this->second = rhs.second;
    return *this;
}

template<typename ret_type = boost::disable_if<boost::is_array<T>, T>::type, typename = void>
pair<ret_type>& operator=(pair<ret_type> const& rhs)
{
    this->first = rhs.first;
    this->second = rhs.second;
    return *this;
}

template<typename temp_type = T, typename boost::enable_if<boost::is_array<temp_type>, temp_type>::type = 0>
pair<T>& operator=(pair<temp_type> const& rhs)
{
    this->first = rhs.first;
    this->second = rhs.second;
    return *this;
}

思想?

2 个答案:

答案 0 :(得分:1)

别忘了,转换分配可以通过模板功能实现,但复制和移动分配操作符不能。

  

用户声明的复制赋值运算符X::operator=是类X的非静态非模板成员函数,其中只有一个X类型的参数,X&const X&volatile X&const volatile X&

     

如果类定义没有显式声明一个复制赋值运算符,则会隐式声明一个。如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制赋值运算符被定义为已删除;否则,它被定义为默认

     

用户声明的移动分配运算符X::operator=是类X的非静态非模板成员函数,其中只有一个X&&类型的参数,const X&&volatile X&&const volatile X&&

和笔记

  

因为模板赋值运算符或赋予rvalue引用参数的赋值运算符永远不是复制赋值运算符,所以这种赋值运算符的存在不会抑制复制赋值运算符的隐式声明。此类赋值运算符与其他赋值运算符(包括复制赋值运算符)一起参与重载解析,如果选择,则将用于分配对象。

(上文第12.8节中的引文,来自n3936草案的措辞)

答案 1 :(得分:1)

为什么你的尝试无法工作在@BenVoigt的答案中解释,这里只是一个替代解决方案。您可以根据模板实例化的类型将operator=调用分派给适当的重载:

#include <iostream>
#include <boost/type_traits.hpp>

template <typename T>
class pair
{    
public:    
    pair& operator=(pair const& rhs)
    {
        return assign(rhs, boost::is_array<T>());
    }

private:
    pair& assign(pair const&, boost::true_type)
    {
        std::cout << "array" << std::endl;
        return *this;
    }

    pair& assign(pair const&, boost::false_type)
    {
        std::cout << "not array" << std::endl;
        return *this;
    }
};

int main()
{
    pair<int> a, b;
    b = a;

    pair<int[]> c, d;
    c = d;
}

输出:

not array
array

你可以对构造函数做同样的事情,将调用委托给(C ++ 11)另一个:

pair() : pair(boost::is_array<T>()) {}

pair(boost::true_type) { /*initialize array pair*/ }

pair(boost::false_type) { /*initialize non-array pair*/ }

代码看起来更清晰,您无需与上的编译器竞争,其中operator=更符合实际参数

DEMO