【问题标题】:Using std::enable_if使用 std::enable_if
【发布时间】:2014-08-29 12:06:25
【问题描述】:

我正在尝试使用 std::enable_if 为一系列类型专门化一个函数。
这是我想要完成的一个更简单的版本。

#include <type_traits>
#include <string>

struct Ip
{};

template <typename T>
bool Equal(const std::string& s, const T& data)
{return s == data;}

template <typename T>
bool Equal(const std::string& s, const typename std::enable_if<std::is_integral<T>::value, T>::type& data)
{
    //int specific
}

template <typename T>
bool Equal(const std::string& s, const typename std::enable_if<std::is_floating_point<T>::value, T>::type& data)
{
    //Float specific
}

//Specialization
template <> bool Equal(const std::string& s, const Ip& data)
{
   //Ip specific
} 

int main()
{
    //Equal("21",21); // Do not compile
    Equal("21","42.5"); // Compile
}

但是在尝试编译时,带有 std::enable_if 的模板函数似乎没有参与解析,因此编译器告诉我没有与我的函数调用匹配的函数。我尝试将std::enable_if 与返回类型一起使用,但也没有运气。我确定我在这段代码中做错了什么,或者我试图以错误的方式做到这一点。
我试图不编写每个 int 特化(int、short、long、很长很长,...),那么有人有解决方案吗?

【问题讨论】:

  • 我想为什么它不起作用在这里解释gotw.ca/publications/mill17.htm
  • @Slava:他似乎没有尝试使用模板特化。
  • @Slava:最后一个案例的好链接(Ip 的专业化),但其他案例有其他问题。

标签: c++ templates c++11 enable-if


【解决方案1】:

我将对您的代码进行几处更改,从不受约束的函数模板开始。由于您要单独处理算术类型,因此只有在 T 既不是整数也不是浮点时才应该选择它。

template <typename T>
typename std::enable_if<!std::is_integral<T>::value &&
                        !std::is_floating_point<T>::value, bool>::type 
    Equal(const std::string& s, const T& data)
{return s == data;}

现在,您为整数和浮点类型定义 Equal 的方式导致 T 成为非推导上下文。因此,将enable_if 移动到一个虚拟模板参数以允许推断(您也可以使用返回类型,如上)。

template <typename T,
          typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr>
bool Equal(const std::string& s, const T& data)
{
    //int specific
    return false;
}

template <typename T,
          typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr>
bool Equal(const std::string& s, const T& data)
{
    //Float specific
    return false;
}

最后,不需要专门处理Ip,而是创建一个重载。

//Overload
bool Equal(const std::string& s, const Ip& data)
{
   //Ip specific
    return false;
}

Live demo

【讨论】:

  • 谢谢,很好的答案,但我在 Visual 2012 中,默认模板参数不可用。我在返回类型中使用 std::enable_if ,它可以工作。两者有区别吗?
  • @Kiroxas 在我看来,在模板参数中使用它会使函数签名更具可读性。但除此之外,功能上没有任何区别。
【解决方案2】:

以下作品:(https://ideone.com/G1vJKm)

#include <string>
#include <type_traits>

struct Ip
{
    std::string ip;
};

template <typename T>
typename std::enable_if<!std::is_integral<T>::value && !std::is_floating_point<T>::value, bool>::type
Equal(const std::string& s, const T& data)
{return s == data;}

template <typename T>
typename std::enable_if<std::is_integral<T>::value, bool>::type
Equal(const std::string& s, const T& data)
{
    //int specific
    return false;
}

template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
Equal(const std::string& s, const T& data)
{
    //Float specific
    return false;
}

bool Equal(const std::string& s, const Ip& data)
{
   //Ip specific
    return false;
}

在你的情况下,

template <typename T>
bool Equal(const std::string& s, const T& data)

是所有T 的有效候选者,也适用于整数和浮点。

您的其他模板函数,编译器无法为typename std::enable_if&lt;std::is_integral&lt;T&gt;::value, T&gt;::type 推断类型T

对于Ip 版本,更简单的重载就足够了(并且是首选)。

【讨论】:

    猜你喜欢
    • 2016-04-27
    • 2012-10-26
    • 1970-01-01
    • 2013-06-03
    • 2016-02-25
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    • 2021-11-10
    相关资源
    最近更新 更多