std :: is_same-从integral_constant

时间:2019-05-26 20:33:37

标签: c++ templates c++17 constexpr

看一下std::is_same的实现,我们可以看到一些内部函数(从integral_constant继承)。为了方便起见,让我复制g ++代码:

  template<typename _Tp, _Tp __v>
  struct integral_constant {
      static constexpr _Tp                value = __v;
      typedef _Tp                         value_type;
      typedef integral_constant<_Tp, __v> type;
      constexpr operator value_type()   const noexcept { return value; }
      constexpr value_type operator()() const noexcept { return value; }
  };

  template<typename, typename>
  struct is_same : public integral_constant<bool, false> { };

  template<typename _Tp>
  struct is_same<_Tp, _Tp> : public integral_constant<bool, true> { };

这为我们提供了几种使用方法的选择:

  bool a1 = is_same<int, int>{};               // instantiate & then cast implicitly
  bool a2 = is_same<int, int>();               // instantiate & then cast implicitly
  bool a3 = is_same<int, int>::value;          // use static member
  bool a4 = is_same<int, int>{}();             // instantiate & then use operator() 
  bool a5 = is_same<int, int>{}.operator()();  // instantiate & then use operator()

我想知道这些额外功能的用例是什么,为什么会这样?

之类的简短实现
  template<class, class> constexpr bool is_same = false;
  template<class T> constexpr bool is_same<T,T> = true;

不够吗?然后我们可以只写bool a = is_same<int,int>而不用{}()::value

任何想法都很感激。

1 个答案:

答案 0 :(得分:3)

这个答案在很大程度上是历史性的。类型特征比变量模板要早十年,因此您建议的选择是过时的。出于可用性方面的考虑,其余部分被逐个添加。


std::integral_constant早在2003年就通过N1424引入。所以这是非常古老的技术,C ++ 03技术。当时看起来像这样:

template <class T, T v> 
struct integral_constant
{
   static  const T                value = v;
   typedef T                      value_type;
   typedef integral_constant<T,v> type;
};

您没有看到任何其他成员函数,请注意,value也只是static const,而不是static constexpr。毕竟还没有constexpr

很多年后,在C ++ 0x的开发过程中,出现了一个库问题(LWG1019),由于新增了constexpr,该问题扩展到:

template <class T, T v>
struct integral_constant {
  static constexpr T value = v;
  typedef T value_type;
  typedef integral_constant<T,v> type;
  constexpr operator value_type() { return value; }
};

N2976已解决此问题。

使用转换函数的动机是它使您可以将integral_constant类型的对象用作这些值。对于某些元编程样式,如果您有直接返回true_type的函数,则可以直接使用它:

std::true_type foo();    
if (foo()) { ... }

不必写if (foo().value)或类似的东西。但是,对于非布尔常量,从对象中获取值的唯一方法是访问value成员或进行显式强制转换(后者要求您知道类型):

constant.value
static_cast<???>(constant)

导致N3545,在2013年,添加了call运算符,使您可以编写constant()来拉回值。最后添加的内容真的有用吗?我不知道。

值得注意的是,所有这些 predates 变量模板-其第一个修订版为N3615。您建议将is_same用作变量bool模板的选项直到后来才成为选项。即使使用变量模板,使用不同的类型也很方便,因此即使有可能,我也不确定我们会走这条路线。回想起来很难说。