代码之家  ›  专栏  ›  技术社区  ›  cigien Jorge Eldis

函数模板实例化的sfinae

  •  0
  • cigien Jorge Eldis  · 技术社区  · 4 年前

    template<typename T> void f() { T{}; }
    

    我想断言 f<int> 是可实例化的,并且 f<S> 不是,在哪里 S 会导致 f 如果实例化编译失败,请说:

    struct S { ~S() = delete; };
    

    似乎我不能使用通常的sfinae方法来实现这一点,因为没有检查函数体是否存在演绎失败。这是你的答案 attempt 玩。

    的确, temp.deduct.8

    只有函数类型、其模板参数类型及其显式说明符的直接上下文中的无效类型和表达式才能导致演绎失败。

    注意:目的是避免要求实现处理涉及任意语句的替换失败。

    如果我的理解是正确的,而这样做是不可能的,我能得到一个解释吗 是否存在此约束?我 认为 任意的 表达 可以由用户检查替换失败,那么为什么这对于实现来说太多了呢?

    如果我误解了这一点 如果可能的话,我能解决这个问题吗?

    0 回复  |  直到 4 年前
        1
  •  1
  •   xmh0511    4 年前

    正如你在问题中所说的,SFINAE只发生在“即时上下文”中,“扣除失败”所包含的情况列在下面 [temp.deduct] . 代码中发生的错误将是格式错误,标准中提到了这一点:

    对类型和表达式的替换可能导致诸如类模板专门化和/或函数模板专门化的实例化、隐式定义函数的生成等效果。此类效果不在直接上下文中,并且可能导致程序格式错误。

    因此,当需要为类型实例化函数模板f时,您的程序将是格式错误的 S .

    解决方案:

    #include <iostream>
    #include <type_traits>
    
    template<typename T> void f() { T a{}; }
    
    struct S { ~S() = delete; };
    struct Test{};
    
    template<typename T,typename U = void>
    struct is_sutable_type_for_function:std::false_type{};
    
    template<typename T>
    struct is_sutable_type_for_function<T,std::void_t<decltype(T{}.~T())>>:std::true_type{};
    
    int main()
    {
       std::cout<< is_sutable_type_for_function<S>::value<<"\n";
       std::cout<< is_sutable_type_for_function<Test>::value<<"\n";
    }
    

    f

        2
  •  0
  •   Community Mofi    4 年前

    在C++中,必须将约束放在函数本身上,以便检测工作:

    Demo (C++ 20)

    #include <type_traits>
    
    template<typename T> void f() requires std::is_constructible_v<T> { T{}; }
    
    template<class T, class = void>
    struct can_call_f : std::false_type{};
    
    template<class T>
    struct can_call_f<T, std::void_t<decltype(f<T>())>>: std::true_type{};
    
    template<class T>
    constexpr bool can_call_f_v = can_call_f<T>::value;
    
    struct S { ~S() = delete; };
    int main()
    {
      static_assert(can_call_f_v<int>);
      static_assert(!can_call_f_v<S>);
    }
    

    回想一下C++的工作原理 类型