9

我试图了解如何使用 C++(11) <type_traits>

这是我的简单测试程序

#include <type_traits>

template<class U, class S>
inline U add(typename std::enable_if<std::is_unsigned<U>::value,U>::type a,
             typename std::enable_if<std::is_signed  <S>::value,S>::type b)
{
    return a + b;
}

int main(int argc, const char * argv[], const char * envp[])
{
    unsigned int ui;
    int i;
    auto a = add(ui, i);
    return 0;
}

使用 GCC 4.8.1 编译时,错误为

/home/per/f.cpp: In function ‘int main(int, const char**, const char**)’:
/home/per/f.cpp:15:23: error: no matching function for call to ‘add(unsigned int&, int&)’
     auto a = add(ui, i);
                       ^
/home/per/f.cpp:15:23: note: candidate is:
/home/per/f.cpp:5:10: note: template<class U, class S> U add(typename std::enable_if<std::is_unsigned<U>::value, U>::type, typename std::enable_if<std::is_signed<S>::value, S>::type)
 inline U add(typename std::enable_if<std::is_unsigned<U>::value,U>::type a,
          ^
/home/per/f.cpp:5:10: note:   template argument deduction/substitution failed:
/home/per/f.cpp:15:23: note:   couldn't deduce template parameter ‘U’
     auto a = add(ui, i);
                       ^

我不知道为什么 GCC 不能推断出模板参数U。任何人都知道我的代码缺少什么信息,这就是我如何在 C++11 中编写一个程序,将无符号整数类型作为第一个参数,将有符号整数类型作为第二个参数?

4

5 回答 5

13

typename std::enable_if<std::is_unsigned<U>::value,U>::type不是可演绎的上下文。为了从中推断U,编译器需要能够应用std::enable_if. 看起来并不太难,这是真的,但那是因为你在谈论一个简单的事情,比如enable_if. 不可能对每个特征都要求这一点,因此 C++ 只是玩得很​​酷,并且不会产生任何奇怪的规则例外:它通常不可推断,在这一点中不可推断。

你可以这样做:

template<class U, class S,
         EnableIf<std::is_unsigned<U>, std::is_signed<S>>...>
U add(U a, S b)

或者在不正确支持该样式的编译器中,您可以添加一个额外的默认参数:

template<class U, class S>
U add(U a, S b,
      typename std::enable_if<std::is_unsigned<U>::value
          && std::is_signed<S>::value,void>::type* = nullptr)

...或弄乱返回类型。

template<class U, class S>
typename std::enable_if<std::is_unsigned<U>::value
    && std::is_signed<S>::value,U>::type
add(U a, S b)
于 2013-06-07T14:20:33.617 回答
8

你没有给编译器一个推断的机会U和的机会S。您可以按如下方式重写您的函数,并在模板参数列表中移动 SFINAE 检查:

template<class U, class S,
    typename std::enable_if<std::is_unsigned<U>::value &&
                            std::is_signed  <S>::value
        >::type* = nullptr>
inline U add(U a, S b)
{
    return a + b;
}

这是一个活生生的例子

于 2013-06-07T14:19:41.227 回答
4

在推理类型之前,您首先必须推断类型!

它应该是:

template <typename U, typename S>
typename std::enable_if<std::is_unsigned<U>::value &&
                        std::is_signed<S>::value>, U>::type
add(U u, S s)
{
    // ...
}
于 2013-06-07T14:19:29.260 回答
2

尝试:

template<class U, class S>
typename std::enable_if<std::is_unsigned<U>::value && std::is_signed<S>,U>::type  
add(U a , S b)
{
    return a + b;
}
于 2013-06-07T14:22:58.913 回答
2

不可能从“嵌套 typedef”表达式中推导出模板参数。也就是说,可以从 推断Usome_template<U>但不能从推断some_template<U>::type

编译器不可能枚举所有(无限!)实例化some_template并查看其中嵌套的 typedef 等于实际参数类型。

于 2013-06-07T14:17:29.087 回答