Is it safe to change the signature of function pointers and call it to ignore the return type?

Our codebase has callbacks that are stored using (for example std::function<void()>

). Sometimes, we would like to bind a function with a different signature to a callback that can be done with bind. This works great for different function parameters, but trying to bind a function that returns something to a callback waiting to return void doesn't work, see here .

The simplest solution we have found is to pass the function of the bound function to the function with the same parameters, but the return type is void:

#include <functional>
#include <iostream>

int ReturnInt()
{
  std::cout << "ReturnInt" << std::endl;
  return 5;
}

struct Struct
{
  int ReturnInt()
  {
    std::cout << "Test::Func" << std::endl;
    return 30;
  }
};

template<typename ReturnType, typename ... ArgumentTypes>
auto IgnoreResult(ReturnType (*i_Func)(ArgumentTypes ...))
  -> void (*)(ArgumentTypes ...)
{
  return reinterpret_cast<void (*)(ArgumentTypes ...)>(i_Func);
}

template<typename ReturnType, typename ClassType, typename ... ArgumentTypes>
auto IgnoreResult(ReturnType (ClassType::*i_Func)(ArgumentTypes ...))
  -> void (ClassType::*)(ArgumentTypes ...)
{
  return reinterpret_cast<void (ClassType::*)(ArgumentTypes ...)>(i_Func);
}


int main(int argc, char **argv)
{
  std::function<void ()> BoundType;

  Struct instance;
  BoundType = std::bind(IgnoreResult(&Struct::ReturnInt), &instance);
  BoundType();

  BoundType = std::bind(IgnoreResult(&ReturnInt));
  BoundType();

  return 0;
}

      

This has been tested with Visual Studio 2013 Nov CTP , cygwin clang 3.4.2 and cygwin gcc 4.8.3 and works on all platforms, but a function pointer call that was added to a different function signature is undefined behavior.

I know some calling conventions might break it, but as far as I can tell from Microsoft calling conventions, the return type is passed through register not through the stack. We also never specify different calling conventions and always use the defaults.

Assuming the gcc , clang and Microsoft compilers do not change their behavior, is it safe to use this to ignore the return type of the function when binding the callback?

+3


source to share


3 answers


Is it safe to change the signature of function pointers and call it to ignore the return type?

No it is not, cf C ++ standard, section § 5.2.10 [expr.reinterpret.cast]

The effect of calling a function using a pointer to a function type (8.3.5) that is not the same as the type used in the function definition is undefined.



Even if it seems to work on a specific compiler / platform, nothing guarantees that it really is (hidden side effects, stack corruption ...).

You should consider a new design in which this selection is not needed in the first place (difficult to answer without additional context)

+4


source


You can use lambdas:



#include <functional>
#include <iostream>

int ReturnInt()
{
  std::cout << "ReturnInt" << std::endl;
  return 5;
}

struct Struct
{
  int ReturnInt()
  {
    std::cout << "Test::Func" << std::endl;
    return 30;
  }
};

int main(int argc, char **argv)
{
  std::function<void ()> BoundType;

  Struct instance;
  BoundType = [&instance] { instance.ReturnInt(); };
  BoundType();

  BoundType = [] { ReturnInt(); };
  BoundType();

  return 0;
}

      

+4


source


You can solve your problem using an approach similar to that used in libsigC ++ 2 (via sigc :: hide_return ()).

+3


source







All Articles