0

I have the following code I try to build with c++11 on XCode 5.1:

template<class T>
float calc2(std::function<float(T)> f) { return -1.0f * f(3.3f) + 666.0f; }

int main(int argc, const char* argv[])
{
    calc2([](float arg) -> float{ return arg * 0.5f; }); //(1) - Will not compile - no matching function...
    calc2<float>([](float arg) -> float{ return arg * 0.5f; }); // (2) - Compiles well
    return 0;
}

Can someone explain why (1) does not compile? Shouldn't the compiler deduce T from the lambda definition?

Thanks!

Mark S
  • 235
  • 3
  • 11
  • `std::function` may be a misnomer, it is a function wrapper. Lambda expressions have unique types unrelated to `std::function`, therefore, template type deduction cannot succeed. – dyp May 04 '14 at 13:46
  • Related: http://stackoverflow.com/q/14784441/420683 – dyp May 04 '14 at 13:49
  • You can only deduce from things you pass in directly, not from things that might be convertible to other things. E.g. try `calc2(std::function([](float arg){return arg/2;}))`. – Kerrek SB May 04 '14 at 13:50
  • So what is the correct way if I want to enforce the input/output parameters of the function/lambda that calc2 receives? – Mark S May 04 '14 at 13:50
  • 1
    That would be something like a concept. Unfortunately, that cannot be done easily in C++11. You can, for example, try `template::type, float>{} >::type> float calc2(F f);` – dyp May 04 '14 at 13:54

1 Answers1

1

Sometimes nothing is the right thing to do. C++ type system will do the dirty work for you:

template<class F>
float calc2(F f)
{
  return -1.0f * f(3.3f) + 666.0f;
}

If you pass it anything that would make the function invalid, it will naturally fail to compile.

The downside is that if you pass it anything that would not make the function invalid, it will compile, even if it makes no sense. If you want to be more selective, you can use static_assert:

#include <type_traits>

template<class F>
float calc2(F f)
{
  static_assert(std::is_same<float, decltype(f(std::declval<float>()))>::value,
                "The argument must return float when called with float arg!");

  return -1.0f * f(3.3f) + 666.0f;
}
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243