问题 如何使用enable_if根据类的模板参数启用成员函数


在代码中:

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。我在想的是我可以在编译期间从一组成员函数中启用一个或第二个成员函数,但它不起作用。任何人都可以向我解释如何正确地做到这一点?
编辑
我真的无法理解的是为什么不存在 typedef 在其中一个def。编译器找不到它,它不会编译它。


12861
2017-11-11 20:00


起源



答案:


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

你要么需要

  • 使成员函数成为成员函数模板而使用 enable_if 在成员函数模板的模板参数或

  • 移动成员函数 f 进入策略类并使用专门化类模板 enable_if


13
2017-11-11 20:07



你能提供一些例子吗? - There is nothing we can do
@There:有一个使用第二种方法(专门化一个类模板)的例子 提升 enable_if 文件 (见3.1节)。 - James McNellis
谢谢你的链接。现在去读它。 - There is nothing we can do


答案:


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

你要么需要

  • 使成员函数成为成员函数模板而使用 enable_if 在成员函数模板的模板参数或

  • 移动成员函数 f 进入策略类并使用专门化类模板 enable_if


13
2017-11-11 20:07



你能提供一些例子吗? - There is nothing we can do
@There:有一个使用第二种方法(专门化一个类模板)的例子 提升 enable_if 文件 (见3.1节)。 - James McNellis
谢谢你的链接。现在去读它。 - There is nothing we can do


您可以使用修改后的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
2017-07-11 13:39



+1,虽然我通常会尽量避免使用下划线开始名称,因为有些规则在某些情况下保留以一个或两个下划线开头的任何名称。还有,你有一个命名函数的原因 _ctor 而不只是定义一个构造函数? - SirGuy
因为我记得下划线用于显示某些东西的本地实现,_ctor只是我的代码中的方法名称,我没有费心重命名 - Alexander77
从 cppreference: 也, 在任何位置包含双下划线__的所有标识符 并且始终保留以下划线后跟大写字母开头的每个标识符,并且保留以下划线开头的所有标识符以用作全局命名空间中的名称。请参阅标识符以获取更多详  所以至少你的 __enable_if 应重命名模板以确保它永远不会干扰任何标准库实现细节。 - SirGuy
或者您可以在命名空间中定义它 - Alexander77


这是它的工作原理(请注意,为方便起见,我更换了你的 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。有关详细信息,请参阅 这个问题


0
2018-02-15 22:28





enable_if需要一个元函数。要使用bool,您需要enable_if_c。我很惊讶你没有得到解释这个问题的错误。

你可以通过在其中声明一个'type'typedef来修复你的元函数。然后你可以使用 boost::enable_if<is_builtin<T>>::type


-2
2017-11-11 20:35



我使用std :: enable_if - There is nothing we can do