如何为同一个函数指针设置不同的函数签名?

时间:2015-01-23 22:40:34

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

如何根据某些条件为具有不同签名的函数设置函数指针?

示例:

short int A() 
{
    return 0;
}

long int B()
{
    return 0;
}

void main()
{
   std::function<short int()> f = A;
   f();
   if(true)
   {
      //error
      f = B;
   }
}

如何为具有不同签名的两个函数使用相同的函数指针? 有可能吗?

如果不是,有一种有效的方法可以根据行为调用相应的函数而不是使用变量并使用if语句拆分整个代​​码?

编辑/扩展(&#34;第二案例&#34;)

#include <SDL.h>

class Obj { //whatever ...}

class A 
{
private:
    Uint16 ret16() { return SDL_ReadLE16(_pFile); }
    Uint32 ret32() { return SDL_ReadLE32(_pFile); }
    _pFile = nullptr;
public:
    Obj* func() 
    {
        Obj obj = new Obj();
        _pFile = SDL_RWFromFile("filename.bin","r"));
        auto ret = std::mem_fn(&SHPfile::ret16); 
        if(true)
        {
            ret = std::mem_fn(&SHPfile::ret32);          
        }

        //ret();
        // continue whatever
        // ....
        SDL_RWclose(_pFile);
        return *obj;
    }
}

我使用Uint16库的Uint32SDL 2变量,使用std::mem_fn

对类似案例进行了编译错误

编译器给我这个错误(相对于我的代码,但是它的实现方式类似于上面的例子):

error: no match for ‘operator=’ (operand types are ‘std::_Mem_fn<short unsigned int (IO::File::*)()>’ and ‘std::_Mem_fn<unsigned int (IO::File::*)()>’)

要解决此编译错误,我强制该函数返回int类型。

有更好的方法吗?

或者我做错了什么?

3 个答案:

答案 0 :(得分:4)

评论已经说clang按原样接受代码,我现在可以说GCC 4.8.4和GCC 4.9.2也都接受了,在修复void main()之后说int main()

std::function的使用完全有效。 C ++ 11标准说:

  

20.8.11.2班级模板功能[func.wrap.func]

function& operator=(const function&);
function& operator=(function&&);
function& operator=(nullptr_t);

此处没有模板赋值运算符,因此B的赋值只能构造一个新的临时function<short int()>对象,并从中移动赋值。确定是否可以构建该临时建筑:

  

20.8.11.2.1 function construct / copy / destroy [func.wrap.func.con]

template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
     

7 要求: F应为CopyConstructible。对于参数类型fCallable应为ArgTypes(20.8.11.2),并返回类型RA的拷贝构造函数和析构函数不会抛出异常。

     

20.8.11.2班级模板功能[func.wrap.func]

     

2类型为f的可调用对象F对于参数类型CallableArgTypes,如果表达式为 {{1,则返回类型R被视为未评估操作数(第5条)的 INVOKE形式良好(20.8.2)。

     

20.8.2要求[func.require]

     

2将 (f, declval<ArgTypes>()..., R) INVOKE定义为 (f, t1, t2, ..., tN, R) INVOKE隐式转换为(f, t1, t2, ..., tN)。< / p>      

1定义 R INVOKE,如下所示:

     
      
  • ... (所有与指向成员的指针类型相关)
  •   在所有其他情况下
  • (f, t1, t2, ..., tN)
  •   

简而言之,这意味着f(t1, t2, ..., tN)可以与任何可以不带参数调用的函数一起使用,并且具有可以隐式转换为std::function<short int()>的返回类型。 short显然可以隐式转换为long,因此没有任何问题。

如果您的编译器库不接受它,并且您无法升级到更新版本,则可以尝试short替代。

Aaron McDaid指出lambda是另一种选择:如果你的图书馆boost::function缺乏,你可以写

std::function

但是如果你采取这种方式,你可以更进一步,完全避免std::function<short int()> f = A; f = []() -> short int { return B(); };

std::function

这是有效的,因为不捕获任何内容的lambas可以隐式转换为与lambda的参数和返回类型匹配的指针到函数类型。实际上,这是写作的简称

short int (*f)() = A;
f = []() -> short int { return B(); };

注意:从short int B_wrapper() { return B(); } ... f = B_wrapper; long的转换可能会丢失数据。如果您想避免这种情况,可以改用shortstd::function<long int()>

答案 1 :(得分:0)

不,你不能用静态类型的语言做到这一点,除非你的类型都有一个共同的超类型,而C ++没有基元的类型。您需要将它们装入一个对象,然后让该函数返回该对象。

然而,如果你这样做,你也可以只保留一个对象指针并使用它而不是函数指针,特别是因为它会更容易实际做一些有用的结果,而不需要全部执行转换这个地方。

例如,在我用Java编写的计算器中,我希望尽可能地使用BigInteger分数来保持精度,但是对于返回无理数的操作,回退到双精度数。我创建了一个Result接口,其中包含BigFractionResultDoubleResult个实现。 UI代码会调用Result sum = firstOperand.add(otherOperand)之类的内容,而不必关心它正在使用的add实现。

答案 2 :(得分:-1)

最清晰的选择是模板:

#include <iostream>
using namespace std;

template <typename T>
T foo() {
    return 0;
}

int main() {
    long a = foo<long>();
    cout << sizeof a << " bytes with value " << a << endl;

    int b = foo<int>();
    cout << sizeof b << " bytes with value " << b << endl;

    short c = foo<short>();
    cout << sizeof c << " bytes with value " << c << endl;

    return 0;
}

在ideone.com中输出:

4 bytes with value 0
4 bytes with value 0
2 bytes with value 0

希望这就是你所需要的。


如果由于某种原因你真的需要传递一个实际的函数,我建议你查看std :: function并尝试使用它编写一些模板代码。

相关问题