【问题标题】:How to create a function pointer having a function signature, possibly at compile time如何创建具有函数签名的函数指针,可能在编译时
【发布时间】:2019-09-25 14:09:18
【问题描述】:

我确实知道this

但是,我没有要比较的两个函数,我有一个函数签名和一个函数指针

template<typename T, typename ... A>
using RequiredSignature = bool(T&, A ... a);

template<typename T, typename ... A>
using RequiredFP = bool(*)(T&, A ... a);

问题:如何确保我收到的函数指针确实确认了所需的签名?在编译时。

【问题讨论】:

  • 也许std::is_copy_assignable&lt;decltype(&amp;ok_fun), RequiredSignature&lt;int&gt;*&gt; ?
  • 但是您是否尝试过简单地将有问题的行更改为 required_sig* rfp; /* defines a function pointer */
  • @BenVoigt 所有好的想法都很简单......让我试试......
  • @BenVoigt 并且它有效。太明显了,无法注意到。谢谢。
  • @BenVoigt 我想的另一个解决方案是使用std::common_type&lt; signature, decltype(fp)&gt; ...但是如果::type 存在,则需要一点SFINAE编号才能返回true ..这更简单。

标签: c++


【解决方案1】:

当你的意思是控制类型时,更好的解决方案是不要使用模板参数推导加上一个虚拟参数。只需将类型传递给需要它的模板参数...

template<typename T, typename U>
constexpr inline bool fp_matches_fp(U y)
{
    T* x{};
    return (sizeof(is_same_helper(x, y))) == (sizeof(yes));
}

你使用它就像

fp_matches_fp<required_sig>(ok_fun)

调用者不必创建一个虚拟函数指针,类型特征会处理它。但是我们根本不需要虚拟函数指针……

template<typename T>
yes& is_compatible_helper(T*);  //no need to define it now!

template<typename T>
no& is_compatible_helper(...); //no definition needed!

template<typename T, typename U>
constexpr inline bool fp_matches_fp(U y)
{
    return (sizeof(is_compatible_helper<T>(y))) == (sizeof(yes));
}

【讨论】:

  • 你打败了我 :)
【解决方案2】:

2

我将此添加为“另一个”答案,以便每个答案都更清楚。

    // https://stackoverflow.com/a/18682805/10870835
template<typename T>
class has_type
{
    typedef struct { char c[1]; } yes;
    typedef struct { char c[2]; } no;

    template<typename U> static constexpr yes test(typename U::type);
    template<typename U> static constexpr no  test(...);

public:
    static constexpr bool result = sizeof(test<T>(nullptr)) == sizeof(yes);
};

template<typename SIG, typename FP >
constexpr bool signature_fp_match(FP)
{
    using c_t = common_type< SIG, FP >;
    if (has_type<c_t>::result) return true;
    return false;
}

// usage
 template<typename T, typename ... A>
using RequiredSignature = bool(T&, A ... a);

  bool ok_fun(int& ) { return true; }

  static_assert( signature_fp_match<RequiredSignature<int> >(ok_fun) ) ;

只是,我认为上一个更简单。

【讨论】:

    【解决方案3】:

    1

    解决方案(当然)是 1. 定义和 2. 从给定的函数签名初始化函数指针。

        using required_sig = RequiredSignature<int>;
        /*
          actually define and initialize the required FP
         */
        required_sig* rfp{};
    
        if (inner::fp_matches_fp(rfp, ok_fun))
        {
            // ... MATCH ...
        }
    

    真的太明显了,谢谢 Ben Voight。

    【讨论】:

    • 我认为你最好为“必需的签名”使用一个显式的模板参数,用法看起来像fp_matches_fp&lt;required_sig&gt;(ok_fun)。那么你就不需要虚拟变量或虚拟函数参数了。
    【解决方案4】:

    3

    如果你也有,请投票给我,但这里是第 3 个答案 :) 我可能会删除前两个中的一个,但将它们全部包含 3 + Bens 概念和答案,可以提供很好的时间顺序视图。

    在我的第二个答案中,我使用的是std::common_type。这种变体更现代、更简洁。

        template< class, class = void_t<> >
    struct
        has_type : false_type { };
    
    template< class T >
    struct
        has_type<T, void_t<decltype(declval<T::type>())>> : true_type { };
    
    template<typename SIG, typename FP >
    constexpr inline bool signature_fp_match(FP)
    {
        using c_t = common_type< SIG, FP >;
    
        return has_type<c_t>{}();
    }
    

    这里是用法

        template<typename T, typename ... A>
          using RequiredSignature = bool(T&, A ... a);
    
    bool ok_fun(int& ) { return true; }
    
    static_assert( signature_fp_match< RequiredSignature<int> >(ok_fun) );
    

    或者不那么时髦的变化:

    static_assert( signature_fp_match< bool(int&) >(ok_fun) );
    

    对于更通用的实用程序,将 signature_fp_match 重命名为 have_common_type 或任何您喜欢的名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 2023-03-12
      • 1970-01-01
      • 2018-02-05
      • 2021-07-02
      • 2015-02-13
      相关资源
      最近更新 更多