涉及嵌套模板参数和默认值的模板类型推导

Template type deduction involving nested template parameters and defaults

本文关键字:类型 默认值 参数 嵌套      更新时间:2023-10-16

我有以下代码:

#include <type_traits>
#include <memory>
class CDelegateCore {};
class CDelegate : public CDelegateCore {};
class CEvent
{
   private:
      /// Simple empty enumeration used for enable_if test.
      enum class enabler_t {};
      template<typename T>
      using EnableIf = typename std::enable_if<T::value, enabler_t>::type;
   public:
      CEvent() {}
      ~CEvent() {}
      void operator += (CDelegateCore* func) {}
      template<typename T, typename Deleter, EnableIf<std::is_base_of<CDelegateCore, T>> = enabler_t{}>
      void operator += (std::unique_ptr<T, Deleter> const& func) { *this += func.get(); }
};
int main()
{
    std::unique_ptr<CDelegate> testdel;
    // ... initialize testdel ...
    CEvent EVENT;
    EVENT += testdel;
}

这里的目标是,当我有一个由std::unique_ptr拥有的CDelegate时,将调用使用std::enable_ifCEvent中的+=重载,并推导出std::unique_ptr中的模板参数。

这段代码在GCC和Clang中运行良好,但在MSVC12中失败了。它无法解析函数。有人能告诉我为什么吗?我最初没有unique_ptr deleter的模板参数,它确实有效,但我不确定C++中关于使用默认嵌套模板参数进行类型推导的规则是什么。

我对此不确定,但我相信这是因为VS2013中缺乏对表达式SFINAE的支持。如果将enable_if表达式移动到operator+= 的返回类型,则可以使代码在VS2013(以及gcc和clang)上工作

template<typename T, typename Deleter>
typename std::enable_if<std::is_base_of<CDelegateCore, T>::value>::type
  operator += (std::unique_ptr<T, Deleter> const& func) { *this += func.get(); }

您可以通过将第二个模板参数更改为void来使用EnableIf别名,或者只使用std::enable_if_t(在gcc和clang上需要-std=c++1y)。

实时演示

VS2013支持SFINAE或至少支持其大部分。更改

template<typename T, typename Deleter, EnableIf<std::is_base_of<CDelegateCore, T>> = enabler_t{}>

template<typename T, typename Deleter, class = EnableIf<std::is_base_of<CDelegateCore, T>>>