0
点赞
收藏
分享

微信扫一扫

类模板中成员函数模板的条件编译

古月无语 2023-11-18 阅读 46

在阅读Tick库中的一段代码时,发现一个问题:

template<typename T>
class TestClass {
public:
    template<typename = std::enable_if_t<std::is_integral<T>::value, int>>
    std::false_type Func()
    {   
        return {}; 
    }   

    template<typename = std::enable_if_t<!std::is_integral<T>::value, int>>
    std::true_type Func()
    {   
        return {}; 
    }   
};

TestClass<int> t{}; // error: no type named ‘type’ in ‘struct std::enable_if<false, int>’

编译会出错,疑问是为什么这里不能通过SFINE来排除第二个函数?也就是SFINE为什么没有生效;

首先看下TestClass<int> 的时候发生了什么,先删除第二个函数,通过cppinsight查看得到:

/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
class TestClass<int>
{
  
  public: 
  template<typename type_parameter_0_0 = std::enable_if_t<std::is_integral<int>::value, int>>
  inline std::integral_constant<bool, false> Func();
};

#endif

类模板Func声明进行了实例化,std::is_integral<int>::value中T被int替换,没有了模板参数推导的过程,即std::enable_if_t的参数没有模板参数的依赖,而第二个函数声明实例化过程中:

template<typename = std::enable_if_t<false, int>>
  inline std::integral_constant<bool, true> Func();

std::enable_if_t<false, int>没有对应的类型type,导致编译出错;

SFINE触发的失败为:函数或者类的模板参数替换导致的失败【2】,而std::enable_if_t中T为TestClass的模板参数,并不是Func依赖的模板参数,因此不是SFINE的fail;

This rule applies during overload resolution of function templates: When substituting the explicitly specified or deduced type for the template parameter fails, the specialization is discarded from the overload set instead of causing a compile error.

Only the failures in the types and expressions in the immediate context of the function type or its template parameter types or its explicit specifier(since C++20) are SFINAE errors. If the evaluation of a substituted type/expression causes a side-effect such as instantiation of some template specialization, generation of an implicitly-defined member function, etc, errors in those side-effects are treated as hard errors.

修改代码为:

template<typename T>
class TestClass {
public:
    template<bool privateBool = true, typename = std::enable_if_t<privateBool && std::is_integral<T>::value, int>>
    std::false_type Func()
    {
        return {};
    }
  
    template<bool privateBool = true, typename = std::enable_if_t<privateBool && !std::is_integral<T>::value, int>>
    std::true_type Func()
    {
        return {};
    }
};

TestClass<int> t{};
t.Func();

此时t.Func()就能正确的选择Func而没有编译报错。

参考资料:

【1】模板实例化

【2】https://en.cppreference.com/w/cpp/language/sfinae

举报

相关推荐

0 条评论