【问题标题】:Template argument deduction failed, SFINAE模板参数推演失败,SFINAE
【发布时间】:2016-05-19 14:16:05
【问题描述】:

当我编译这段代码时:

#include <type_traits>

template <typename T>
void do_stuff(std::enable_if_t<std::is_integral<T>::value, T> &t) {}

template <typename T>
void do_stuff(std::enable_if_t<std::is_class<T>::value, T> &t) {}

int main() {
    int i = 1;
    do_stuff(i);
    return 0;
}

GCC 说:

37325975.cpp: In function ‘int main()’:
37325975.cpp:11:15: error: no matching function for call to ‘do_stuff(int&)’
     do_stuff(i);
               ^
37325975.cpp:4:6: note: candidate: template<class T> void do_stuff(std::enable_if_t<std::is_integral<_Tp>::value, T>&)
 void do_stuff(std::enable_if_t<std::is_integral<T>::value, T> &t) {}
      ^
37325975.cpp:4:6: note:   template argument deduction/substitution failed:
37325975.cpp:11:15: note:   couldn't deduce template parameter ‘T’
     do_stuff(i);
               ^
37325975.cpp:7:6: note: candidate: template<class T> void do_stuff(std::enable_if_t<std::is_class<T>::value, T>&)
 void do_stuff(std::enable_if_t<std::is_class<T>::value, T> &t) {}
      ^
37325975.cpp:7:6: note:   template argument deduction/substitution failed:
37325975.cpp:11:15: note:   couldn't deduce template parameter ‘T’
     do_stuff(i);
           ^

我也尝试过 msvc 2013。

为什么会出现这些错误?

Live Demo

【问题讨论】:

    标签: c++ templates sfinae


    【解决方案1】:

    正如编译器所说,该参数类型是不可推导的,因此您需要手动提供模板参数,如下所示:

    do_stuff<int>(i);
    

    更好的选择是将std::enable_if 放在返回类型或模板参数列表中:

    //Return type
    template <typename T>
    std::enable_if_t<std::is_integral<T>::value>
    do_stuff(T &t) {}
    
    template <typename T>
    std::enable_if_t<std::is_class<T>::value> 
    do_stuff(T &t) {}
    
    //Parameter list
    template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
    void do_stuff(T &t) {}
    
    template <typename T, std::enable_if_t<std::is_class<T>::value>* = nullptr > 
    void do_stuff(T &t) {}
    

    这样模板参数还是可以推导出来的:

    do_stuff(i);
    

    【讨论】:

      【解决方案2】:

      为什么会出现这些错误?

      因为嵌套名称说明符的模板参数推导失败,即non-deduced contexts

      使用限定 ID 指定的类型的嵌套名称说明符(范围解析运算符 :: 左侧的所有内容)。

      // the identity template, often used to exclude specific arguments from deduction
      template<typename T> struct identity { typedef T type; };
      template<typename T> void bad(std::vector<T> x, T value = 1);
      template<typename T> void good(std::vector<T> x, typename identity<T>::type value = 1);
      std::vector<std::complex<double>> x;
      bad(x, 1.2);  // P1 = std::vector<T>, A1 = std::vector<std::complex<double>>
                    // P1/A1: deduced T = std::complex<double>
                    // P2 = T, A2 = double
                    // P2/A2: deduced T = double
                    // error: deduction fails, T is ambiguous
      good(x, 1.2); // P1 = std::vector<T>, A1 = std::vector<std::complex<double>>
                    // P1/A1: deduced T = std::complex<double>
                    // P2 = identity<T>::type, A2 = double
                    // P2/A2: uses T deduced by P1/A1 because T is to the left of :: in P2
                    // OK: T = std::complex<double>
      

      【讨论】:

        【解决方案3】:

        当编译器尝试解析do_stuff(int&amp;) 时,它会看到编译器告诉您的两个候选对象。但是它无法“向后工作”找到满足std::enable_if_t&lt;std::is_integral&lt;T&gt;::value, T&gt; == intT,也无法找到满足std::enable_if_t&lt;std::is_class&lt;T&gt;::value, T&gt; == intT

        正如TartanLlama's answer 中提到的,避免这种情况的方法是使参数可推导(例如do_stuff(T&amp;))并使返回类型后续模板参数 依赖于T

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多