使用std :: enable_if作为templ时的默认模板参数.param.:为什么两个模板函数只在enable_if参数中有所不同?

dfr*_*fri 11 c++ templates enable-if c++11

cppreference语言参考中std::enable_if包括以下注释

笔记

一个常见的错误是声明两个仅在默认模板参数上有所不同的函数模板.这是非法的,因为默认模板参数不是函数模板签名的一部分,并且声明具有相同签名的两个不同函数模板是非法的.

在下面的示例中的模板函数中,在我看来,这种情况发生.即,两个模板函数onlyForDerivedObjects(...)似乎(对我来说)仅由它们的默认模板参数不同.我意识到我在这里遗漏了一些东西,希望有人可以向我解释这一点,或者指出我可能会为自己找到顿悟的方向.

  • 问题:上面的引用,为什么下面的例子编译并运行正常:typename std::enable_if ...当我认为它产生两个模板函数的情况时,我在下面的模板函数中错误分类了部分,这两个模板函数的区别仅在于它们的默认模板参数?

基础和派生类:

class BaseA
{
public:
  int getInt() const { return 21; };
};

class DerivedA : public BaseA {};

class BaseB
{
public:
  int getAnotherInt() const { return 33; };
};

class DerivedB : public BaseB {};
Run Code Online (Sandbox Code Playgroud)

具有以下模板功能

/* template functions that, seemingly, only differ in their
   default template arguments? */
template< class T,
          typename std::enable_if<std::is_base_of<BaseA, T>::value>::type* = nullptr >
int onlyForDerivedObjects(const T& obj)
{
  return 2*obj.getInt();
}

template< class T,
          typename std::enable_if<std::is_base_of<BaseB, T>::value>::type* = nullptr >
int onlyForDerivedObjects(const T& obj)
{
  return 3*obj.getAnotherInt();
}
Run Code Online (Sandbox Code Playgroud)

编译并运行良好(g++ -Wall -std=c++11 ...,g++ 4.9.3)

#include <iostream>
#include <type_traits>

/* ... classes and template functions as above */

/* template argument deduction seems to work fine */
int main()
{
  DerivedA* objA = new DerivedA();
  DerivedB* objB = new DerivedB();

  std::cout << onlyForDerivedObjects(*objA) << std::endl; // 42
  std::cout << onlyForDerivedObjects(*objB) << std::endl; // 99

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ely 10

笔记

一个常见的错误是声明两个仅在默认模板参数上有所不同的函数模板.这是非法的,因为默认模板参数不是函数模板签名的一部分,并且声明具有相同签名的两个不同函数模板是非法的.

您的函数在默认模板参数上没有区别,它们的模板参数不同,因此具有不同的签名.

在这两种情况下,默认模板参数都是nullptr,但第二个模板参数在每种情况下都不同.

  • @DawidPilarski 签名包括整个“enable_if”类型,而不仅仅是它在推导后解析的类型。这些类型是不同的,因为它们依赖于不同的表达式(一种使用“is_base_of&lt;BaseA, T&gt;”,一种使用“is_base_of&lt;BaseB, T&gt;”)。 (4认同)

Jar*_*d42 8

常见的错误是:

template <typename T, typename = std::enable_if_t<cond>>
void foo()

template <typename T, typename = std::enable_if_t<!cond>>
void foo()
Run Code Online (Sandbox Code Playgroud)

这两个都宣布

template <typename, typename>
void foo();
Run Code Online (Sandbox Code Playgroud)