【问题标题】:Function pointer with default behaviour具有默认行为的函数指针
【发布时间】:2015-06-03 10:50:55
【问题描述】:

在我的程序中,我有很多指向外部库提供的函数的指针。有的返回值,有的没有。

如果外部库没有提供函数(指针为 NULL)并且函数应该返回值程序应该采用默认值(在编译时已知)。

我试图完成的是减少 if 语句的数量,并使用以下用例将指针包装在类中:

enum E { e1, e2, e3 };
UserFunction<uint8_t(int, int), 0> callback1 { user_function_ptr }; // Calls and returns value of user_function_ptr
UserFunction<uint8_t(), 0> callback2 { nullptr }; // Returns 0
UserFunction<uint8_t(), 1> callback3 { nullptr }; // Returns 1
UserFunction<E(int), e1> callback4 { user_function_ptr2 }; // Returns enum value and takes one integer argument
UserFunction<void(int)> callback5 { user_function_ptr3 }; // No return value, one argument
UserFunction<void()> callback6 { nullptr }; // Should perform noop

到目前为止,我正在为返回值的函数工作:

template <class Sign, int Def>
struct UserF;

template <class R, int Def, class... Args>
struct UserF<R(Args...), Def> {
    typedef R Signature(Args...);
    typedef typename std::add_pointer<Signature>::type SignaturePtr;

    static R Default(Args... args) {
        return (R) Def;
    }

    UserF() {
        functionToCall = Default;
    }

    UserF(SignaturePtr userFunction) {
        if (userFunction != nullptr) {
            functionToCall = userFunction;
        } else {
            functionToCall = Default;
        }
    }

    R operator() (Args... args) {
        return functionToCall(args...);
    }

private:
    SignaturePtr functionToCall;
};

上面代码的问题是它强制默认值为int。我能做的是将UserF 模板更改为这样的:

template <class R, R Def, class... Args>
struct UserF {
    // ...
};
// use case
UserF<E, e1, int> callback; // Returns E, takes int, default e1

但如果可能的话,我宁愿使用

UserF<R(Args...), Default> callback; // preferred
UserF<Default, R(Args...)> callback; // if above is not possible
UserF<void(Args...)> callback; // if no return value

我宁愿不使用std::function,因为我知道我将只处理指向函数的指针,而不是指向成员函数、仿函数对象等的指针。也不允许使用 boost(允许使用 C++11 )。

总而言之,问题是:如何强制对默认返回值进行类型检查。

【问题讨论】:

  • 不能Default 在构造函数中而不是模板参数中?
  • @jarod42 可能应该是,因为它需要体操才能使其与双返回类型(等)一起使用
  • @Jarod42 默认值可以在构造函数中传递,但我认为我提出的语法更简洁。此外,它需要将每个函数指针的默认值存储在内存中。

标签: c++ c++11 function-pointers


【解决方案1】:
template<class Sig>
struct return_type;
template<class Sig>
using return_type_t=typename return_type<Sig>::type;
template<class R,class...Args>
struct return_type<R(Args...)>{
  using type=R;
};

template <class Sign, return_type_t<Sign> Def>
struct UserF;

是大部分。要处理void,您需要一个标志技巧:

struct void_flag{};
template<class T>
using flag_void=
  typename std::conditional<std::is_same<T,void>{},void_flag*,T>::type;

template <class Sign, flag_void<return_type_t<Sign>> Def=nullptr>
struct UserF;

template <class R, R Def, class... Args>
struct UserF<R(Args...), Def>{
  // body

template <class... Args>
struct UserF<void(Args...), 0>{
  // body

非整数非指针R 会出现问题,因为您不能将double 传递给template。一种方法是将double 升级为double const* for Def,并使其自动取消引用:

template <class R, R const* Def, class... Args>
struct UserF<R(Args...), Def>{
  // body

并执行类似flag_void 的操作,将T=double 变成T=double const*

【讨论】:

    【解决方案2】:

    如果你能忍受一个小宏,你可以这样做:

    template <typename sig, typename T, T v >
    struct UserF_;
    
    template <class R, typename ... Args, typename T, T v >
    struct UserF_< R(Args...), T, v > {
        // ...
    };
    #define UserF( F, Default ) UserF_< F, decltype( Default ), Default >
    
    UserF(R(Args...), Default) callback; 
    

    如果没有首先将其类型指定为模板类型参数,则不能拥有通用模板非类型参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 2013-08-08
      • 2013-01-27
      • 2011-05-25
      • 1970-01-01
      • 2016-03-22
      • 2018-01-12
      相关资源
      最近更新 更多