SFINAE works differently in cases of type and non-type template parameters

后端 未结 5 475
遇见更好的自我
遇见更好的自我 2020-11-28 13:25

Why does this code work:

template<
    typename T, 
    std::enable_if_t::value, T>* = nullptr>
void Add(T) {}

templa         


        
5条回答
  •  旧时难觅i
    2020-11-28 13:54

    SFINAE is about substitution. So let us substitute!

    template<
      typename T, 
      std::enable_if_t::value, T>* = nullptr>
    void Add(T) {}
    
    template<
      typename T, 
      std::enable_if_t::value, T>* = nullptr>
    void Add(T) {}
    

    Becomes:

    template<
      class T=int, 
      int* = nullptr>
    void Add(int) {}
    
    template<
      class T=int, 
      Substitution failure* = nullptr>
    void Add(int) {
    
    template<
      class T=double, 
      Substitution failure* = nullptr>
    void Add(double) {}
    
    template<
      class T=double
      double* = nullptr>
    void Add(double) {}
    

    Remove failures we get:

    template<
      class T=int, 
      int* = nullptr>
    void Add(int) {}
    template<
      class T=double
      double* = nullptr>
    void Add(double) {}
    

    Now remove template parameter values:

    template<
      class T, 
      int*>
    void Add(T) {}
    template<
      class T
      double*>
    void Add(T) {}
    

    These are different templates.

    Now the one that messes up:

    template<
      typename T, 
      typename = typename std::enable_if::value, T>::type>
    void Add(T) {}
    
    template<
      typename T, 
      typename = typename std::enable_if::value, T>::type>
    void Add(T) {}
    

    Becomes:

    template<
      typename T=int, 
      typename =int>
    void Add(int) {}
    
    template<
      typename int, 
      typename = Substitution failure >
    void Add(int) {}
    
    template<
      typename T=double, 
      typename = Substitution failure >
    void Add(double) {}
    
    template<
      typename T=double, 
      typename = double>
    void Add(double) {}
    

    Remove failures:

    template<
      typename T=int, 
      typename =int>
    void Add(int) {}
    template<
      typename T=double, 
      typename = double>
    void Add(double) {}
    

    And now template parameter values:

    template<
      typename T, 
      typename>
    void Add(T) {}
    template<
      typename T, 
      typename>
    void Add(T) {}
    

    These are the same template signature. And that is not allowed, error generated.

    Why is there such a rule? Beyond the scope of this answer. I'm simply demonstrating how the two cases are different, and asserting that the standard treats them differently.

    When you use a non-type template parameter like the above, you change the template signature not just the template parameter values. When you use a type template parameter like the above, you only change the template parameter values.

提交回复
热议问题