Wednesday, September 19, 2012

Infer return type for templated function in C++

When I recently played around with ways of implementing generator in a test framework in C++, I had the need to have the compiler infer the return type of a template function. Something long the lines:
template<typename T>
T generate() {
  // generate a value of type T.
}
void test() {
  int integer = generate();
  std:::string str = generate();
}
Unfortunately, this code does not compile as the compiler cannot infer the return type required for the call to generate. There is, however, a way around this -- by using a casting operator.

Casting operator are functions that are used when the compiler tries to convert one type to another. An example of this is follows here:
struct Object {
  operator int() { return 0; }
};
int foo() {
  Object obj;
  return obj;  // 'obj' is implicitly converted to an 'int'.
}
Here, foo will return 0 because that's what Object's casting operator returns.

So, without further ado, here's an example how to emulate return type inference on a template function:
template<typename T>
struct ReturnValue { };

// Specialization for type int. Implements 'T generate()'
// for T == int.
template<>
struct ReturnValue<int> {
  static int value() { return 17; }
};

// Specialization for type std::string. Implements
// 'T generate()' for T == std::string.
template<>
struct ReturnValue<std::string> {
  static std::string value() { return "foo"; }
};

struct ReturnType {
  template<typename T>
  operator T() {
    return ReturnValue<T>::value();
  }
};
ReturnType generate() {
  return ReturnType();
}

void test() {
  int integer = generate(); // = 17
  std::string str = generate(); // = "foo"
}
It's a bit of extra complexity but it works nicely and it makes it possible to separate the implementations of T generate() for different values of T, which is pretty neat.

I wouldn't call this pattern useful in normal application code, but might be useful for APIs or parts of DSLs.

3 comments:

Alexey Shmalko said...

I'm sorry to say, it's not a return type inference. It's function overloading by return type which is quite different.

Alexey Shmalko said...

I'm sorry to say, it's no a return type inference. It's template function overloading by return type, which is quite different.

Torgny said...

You're right, it's not really return type inference.

Analogous to "template argument type deduction", I guess I should have called it "template return type deduction" as that's what I tried to achieve with this.