簡體   English   中英

計算函數指針的類型

[英]Computing the type of a function pointer

考慮以下:

template<typename T>
struct S
{
    typedef M< &T::foo > MT;
}

這將適用於:

S<Widget> SW;

其中Widget::foo()是一些函數

我將如何修改struct S的定義以允許以下內容:

S<Widget*> SWP;

您需要以下類型轉換。

  • 給定T ,返回T
  • 給定T * ,返回T

碰巧的是,標准庫已經在std::remove_pointer為我們實現了這std::remove_pointer (盡管自己做起來並不難)。

有了這個,你可以寫

using object_type = std::remove_pointer_t<T>;
using return_type = /* whatever foo returns */;
using MT = M<object_type, return_type, &object_type::foo>;

關於您還想使用智能指針的評論,我們必須重新定義類型轉換。

  • 給定智能指針類型smart_ptr<T> ,返回smart_ptr<T>::element_type ,應為T
  • 給定指針類型T * ,返回T
  • 否則,給定T ,返回T本身

為此,我們必須編寫我們自己的元函數。 至少,我不知道標准庫中有什么對這里有幫助的。

我們首先定義主要template (“否則”情況)。

template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };

默認為void的第二個(匿名)類型參數將在以后使用。

對於(原始)指針,我們提供以下部分專業化。

template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };

如果我們在這里停止,基本上就可以得到std::remove_pointer 但是,我們將為智能指針添加額外的部分專業化。 當然,我們首先必須定義什么是“智能指針”。 出於本示例的目的,我們將使用嵌套的typedef命名為element_type每個類型作為智能指針。 視需要調整此定義。

template <typename T>
struct unwrap_obect_type
<
  T,
  std::conditional_t<false, typename T::element_type, void>
>
{
  using type = typename T::element_type;
};

第二個類型參數std::conditional_t<false, typename T::element_type, void>是在C ++ 14中模擬std::void_t的復雜方法。 我們的想法是,我們具有以下部分類型函數。

  • 給定類型T的嵌套typedef名為element_type ,返回void
  • 否則,觸發替換失敗

因此,如果我們正在處理智能指針,則將獲得比主template更好的匹配,否則,SFINAE將從進一步考慮中刪除此部分專業化知識。

這是一個工作示例。 TC建議使用std::mem_fn調用成員函數。 這使代碼比我最初的示例干凈得多。

#include <cstddef>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <utility>

template <typename ObjT, typename RetT, RetT (ObjT::*Pmf)() const noexcept>
struct M
{
  template <typename ThingT>
  static RetT
  call(ThingT&& thing) noexcept
  {
    auto wrapper = std::mem_fn(Pmf);
    return wrapper(std::forward<ThingT>(thing));
  }
};

template <typename T, typename = void>
struct unwrap_obect_type { using type = T; };

template <typename T>
struct unwrap_obect_type<T *, void> { using type = T; };

template <typename T>
struct unwrap_obect_type<T, std::conditional_t<false, typename T::element_type, void>> { using type = typename T::element_type; };

template <typename T>
struct S
{

  template <typename ThingT>
  void
  operator()(ThingT&& thing) const noexcept
  {
    using object_type = typename unwrap_obect_type<T>::type;
    using id_caller_type          = M<object_type, int,                &object_type::id>;
    using name_caller_type        = M<object_type, const std::string&, &object_type::name>;
    using name_length_caller_type = M<object_type, std::size_t,        &object_type::name_length>;
    std::cout << "id:          " << id_caller_type::call(thing)          << "\n";
    std::cout << "name:        " << name_caller_type::call(thing)        << "\n";
    std::cout << "name_length: " << name_length_caller_type::call(thing) << "\n";
  }

};

class employee final
{

 private:

  int id_ {};
  std::string name_ {};

 public:

  employee(int id, std::string name) : id_ {id}, name_ {std::move(name)}
  {
  }

  int                  id()          const noexcept { return this->id_; }
  const std::string&   name()        const noexcept { return this->name_; }
  std::size_t          name_length() const noexcept { return this->name_.length(); }

};

int
main()
{
  const auto bob = std::make_shared<employee>(100, "Smart Bob");
  const auto s_object = S<employee> {};
  const auto s_pointer = S<employee *> {};
  const auto s_smart_pointer = S<std::shared_ptr<employee>> {};
  s_object(*bob);
  std::cout << "\n";
  s_pointer(bob.get());
  std::cout << "\n";
  s_smart_pointer(bob);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM