【问题标题】:C++ General Pointer Function or TemplateC++ 通用指针函数或模板
【发布时间】:2018-09-07 21:03:52
【问题描述】:

我如何编写一个函数来兼容 vanilla 指针类型 (T*) 或 <memory> 中定义的特殊指针类型,例如 std::unique_ptr

我尝试使用std::is_pointer 检查,但看起来这不是正确的方法:

#include <iostream>
#include <memory>

template<typename T>
void SomePointerFunction(
     T p, typename std::enable_if<std::is_pointer<T>::value>::type* = nullptr) {
  std::cout << (p ? "not null" : "null") << std::endl;
}

int main() {
  int* p;
  std::unique_ptr<int> q;
  SomePointerFunction(p); // If we cange p to q, template matching fails

  return 0;
}

是否有某种在 C++ 中定义的通用指针类型可以封装这些不同类型的指针,或者可以实现此目的的不同模板检查?


经过更多思考,我也明白为什么这实际上是该语言的一个不良特性,因为这两种类型的指针在很多方面都非常不同。但是,如果您只想编写一个利用指针的解引用属性的函数,那么这似乎很有用。有没有办法说“这个函数接受一个参数,为此定义了运算符*”?

【问题讨论】:

  • 您可能会考虑添加重载void SomePointerFunction(std::nullptr_t) { SomePointerFunction( static_cast&lt;void*&gt;(nullptr) ); },因为nullptr_t 类型在技术上不是指针类型并且不能被取消引用,但通常期望像指针一样工作。
  • 这在很多情况下似乎都很合理,谢谢你的建议!
  • 你也要处理std::nullptr_t吗?

标签: c++ templates pointers


【解决方案1】:

有没有办法说“这个函数有一个参数, 运算符 * 已定义”?

有,只是尝试取消引用它。如果它不起作用,SFINAE 就会启动:

template<typename T, typename = decltype(*std::declval<T>())>

我们使用std::declval 来获取T,取消引用它并尝试获取decltype。最终结果被忽略,我们只需要它编译,这意味着T是可解引用的。

#include <iostream>
#include <memory>

template<typename T, typename = decltype(*std::declval<T>())>
void SomePointerFunction(
     T& p) {
  std::cout << (p ? "not null" : "null") << std::endl;
}

int main() {
  int* p = nullptr;
  std::unique_ptr<int> q;
  int i = 0;
  SomePointerFunction(p);
  SomePointerFunction(q);
  //SomePointerFunction(i);
  /* Above prints:
   main.cpp: In function 'int main()':
   main.cpp:16:24: error: no matching function for call to 'SomePointerFunction(int&)'
   */

  return 0;
}

【讨论】:

  • SomePointerFunction 可能不应该采用T&amp;,因为它不会修改参数。我会使用T 或转发参考T&amp;&amp;
  • 太棒了,这实际上比我预期的更时尚。我只需要阅读更多关于decltypedeclval 的内容——这些总是让我感到困惑,但我认为这是因为我还没有在令人信服的环境中看到它们(对我来说)。
  • @aschepler 我不得不将其更改为T&amp;,因为std::unique_ptr 不可复制,T&amp;&amp; 可能是更好的选择。
  • 我想知道typename = &lt;type&gt; 的语法是什么意思(在第二个模板参数中)。这是typename U = &lt;type&gt; 的匿名简写,其中&lt;type&gt; 将是默认类型,并且不需要该名称,因为它没有在其他地方引用?
  • @Apollys,完全正确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多