繁体   English   中英

使用 enable_if 根据模板类型隐藏成员函数

[英]Using enable_if to hide member function according to template type

如果模板参数匹配特定类型,我希望我的类模板提供一个额外的函数成员。 我正在尝试使用std::enable_if来获得 SFINAE 实现,但我正在努力为此找到正确的语法。 我为类似的问题尝试了几种解决方案,但由于某种原因,它们都没有编译。

#include <type_traits>
#include <string>

template < typename T >
class myClass {
 public:
    using value_type = T;
    using other_type = int;

    myClass() = default;
    virtual ~myClass() = default;

    // 'default' member
    void function(const value_type& val) {};

    // overload #1
    // error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
    template < typename = typename std::enable_if< !std::is_convertible< other_type, value_type >::value >::type >
    void function(const other_type& val) {};

    // overload #2
    // error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
    template < std::enable_if_t< !std::is_convertible< other_type, value_type >::value >* = nullptr >
    void function(const other_type& val) {};
};



int main(int argc, char const *argv[]) {
    myClass< std::string > foo;  // OK
    myClass< float > bar;            // error: no type named ‘type’ in ‘struct std::enable_if<false, void>’

    return 0;
}

我希望function可用于所有类型,但它的重载other_type不能隐式转换为value_type时才可用。 我将如何实施这个?

function成员函数模板重载中, SFINAE 构造 ( std::enable_if_t ) 不包含依赖类型,这意味着没有替换上下文,并且重载的模板头中的失败不是替换失败,它们是硬错误。 记起:

  • SFINAE -替换失败不是错误

您通常通过添加一个虚拟模板参数来解决这个问题,该参数的默认模板参数是您最初直接使用的封闭类模板的模板参数( T ;您的值类型):

template <typename U = T, typename = typename std::enable_if<
                              !std::is_convertible<other_type, U>::value>::type>
void function(const other_type &val){};

template <
    typename U = T,
    std::enable_if_t<!std::is_convertible<other_type, U>::value> * = nullptr>
void function(const other_type &val){};

std::enable_if_t SFINAE 构造现在依赖于每个成员函数模板重载的上下文。

要应用 SFINAE,您需要尝试使用 SFINAE 的对象拥有自己的模板参数,并且您需要在条件中使用该模板参数。 在这种情况下,你可以通过添加一个模板参数修复typename V = value_type的模板参数,并使用V代替value_type 现在条件将取决于V ,它是成员函数的模板参数:

#include <type_traits>
#include <string>

template < typename T >
class myClass {
 public:
    using value_type = T;
    using other_type = int;

    myClass() = default;
    virtual ~myClass() = default;

    // 'default' member
    void function(const value_type& val) {};

    // overload #1
    // error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
    template < typename V = value_type, typename = typename std::enable_if< !std::is_convertible< other_type, V >::value >::type >
    //   added ^^^^^^^^^^^^^^^^^^^^^^^^                                               changed value_type to V ^
    void function(const other_type& val) {};

    // overload #2
    // error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
    template < typename V = value_type, std::enable_if_t< !std::is_convertible< other_type, V >::value >* = nullptr >
    //   added ^^^^^^^^^^^^^^^^^^^^^^^^                             changed value_type to V ^
    void function(const other_type& val) {};
};



int main(int argc, char const *argv[]) {
    myClass< std::string > foo;  // OK
    myClass< float > bar;        // OK

    return 0;
}

由于在 C++20 中引入了概念,大多数 SFINAE 机器都可以简化或至少表达得不那么冗长。

#include <concepts>
#include <iostream>
#include <string>

template < class Type >
class myClass {
 public:
    myClass() = default;

    void function(Type const& val) {
        std::cout << "Default: " << val << "\n";
    }

    template < class Other >
        requires (not std::convertible_to<Other, Type>)  // <- Constrain
    void function(Other const& val) {
        std::cout << "Overload: " << val << "\n";
    }
};



int main()
{
    myClass< std::string > foo;
    foo.function("OK");          // Default
    foo.function(42);            // Overload

    myClass< float > bar;
    bar.function(42);            // Default
    bar.function("OK");          // Overload
    bar.function(3.14);          // Default
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM