【问题标题】:How to use enable_if to enable member functions based on template parameter of class如何使用 enable_if 根据类的模板参数启用成员函数
【发布时间】:2010-11-11 20:00:24
【问题描述】:

在代码中:

template<class T>
struct is_builtin
{
    enum {value = 0};
};

template<>
struct is_builtin<char>
{
    enum {value = 1};
};

template<>
struct is_builtin<int>
{
    enum {value = 1};
};

template<>
struct is_builtin<double>
{
    enum {value = 1};
};

template<class T>
struct My
{
    typename enable_if<is_builtin<T>::value,void>::type f(T arg)
    {
        std::cout << "Built-in as a param.\n";
    }


    typename enable_if<!is_builtin<T>::value,void>::type f(T arg)
    {
        std::cout << "Non - built-in as a param.\n";
    }
};

struct A
{
};

int main()
{
    A a;
    My<int> m;
    My<A> ma;
    m.f(1);
    ma.f(a);
    return 0;
}

我收到一个错误:

error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type>'    

显然我不明白如何使用enable_if。我在想的是,我可以在编译期间从一组成员函数中启用一个或第二个成员函数,但它不起作用。谁能给我解释一下如何正确地做到这一点?
已编辑
我真的不明白为什么在其中一个 def 中没有typedef。编译器找不到它,它不会编译它。

【问题讨论】:

    标签: c++ templates metaprogramming sfinae


    【解决方案1】:

    您不能使用类模板参数来获取成员函数的 SFINAE。

    你要么需要

    • 将成员函数改为成员函数模板,并在成员函数模板的模板参数上使用enable_if

    • 将成员函数f 移动到策略类中,并使用enable_if 特化类模板。

    【讨论】:

    【解决方案2】:

    这是它的工作原理(请注意,为方便起见,我将您的 is_builtin 特征替换为 std::is_arithmetic 并使用了更多 C++11 的东西,但它可以以任何方式工作):

    template<class T>
    struct My
    {
        template<typename T_ = T, std::enable_if_t<std::is_arithmetic<T_>::value>* = nullptr>
        void f(T_ arg)
        {
            std::cout << "Built-in as a param.\n";
        }
    
        template<typename T_ = T, std::enable_if_t<!std::is_arithmetic<T_>::value>* = nullptr>
        void f(T_ arg)
        {
            std::cout << "Non - built-in as a param.\n";
        }
    };
    

    DEMO

    关键部分是通过使用等于类模板参数T 的默认函数模板参数T_ 将模板参数带入直接上下文。详情请见this question

    【讨论】:

      【解决方案3】:

      您可以使用修改后的 enable_if 来修复您的代码

      template < typename T >
      struct __Conflict {};
      
      template <bool B, class T = void>
      struct __enable_if { typedef __Conflict<T> type; };
      
      template <class T>
      struct __enable_if<true, T> { typedef T type; };
      

      使用示例:

      template <typename T>
      class Lazy
      {
      public:
          void _ctor(bool b);
          void _ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type);
      };
      
      template <typename T>
      void Lazy<T>::_ctor(bool b)
      {
          std::cout << "bool " << b << std::endl;
      };
      
      template <typename T>
      void Lazy<T>::_ctor(typename __enable_if<!std::is_same<T, bool>::value, T>::type t)
      {
          std::cout << "T " << t << std::endl;
      };
      
      int main(int argc, char **argv)
      {
          Lazy<int> i;
          i._ctor(10);
          i._ctor(true);
      
          Lazy<bool> b;
          b._ctor(true);
      
          return 0;
      }
      

      【讨论】:

      • +1,尽管我通常会尽量避免以下划线开头的名称,因为在某些情况下,任何以一到两个下划线开头的名称都保留了一些规则。另外,您是否有理由将函数命名为 _ctor 而不仅仅是定义构造函数?
      • 我记得下划线用于显示某些东西的本地实现,_ctor 只是我的代码中的方法名称,我没有费心重命名
      • 来自cppreference另外,在任何位置包含双下划线 __ 的所有标识符 以及以下划线后跟大写字母开头的每个标识符都是始终保留,所有以下划线开头的标识符都保留用作全局命名空间中的名称。有关更多详细信息,请参阅标识符。 因此,至少应该重命名您的 __enable_if 模板,以确保它不会干扰任何标准库实现细节。
      • 或者你可以在命名空间中定义它
      【解决方案4】:

      enable_if 需要一个元函数。要使用布尔值,您需要 enable_if_c。我很惊讶您没有收到解释该问题的错误。

      您可以通过在内部声明一个“类型”typedef 来修复您的元函数,这就是它本身。然后你可以使用boost::enable_if&lt;is_builtin&lt;T&gt;&gt;::type

      【讨论】:

        猜你喜欢
        • 2021-12-26
        • 1970-01-01
        • 2012-10-01
        • 2012-01-22
        • 1970-01-01
        • 1970-01-01
        • 2011-04-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多