#include <functional>
#include <iostream>
#include <type_traits>
#include <utility>

struct Vector3f64 {
  double x;
  double y;
  double z;
};

struct Vector3f32 {
  float x;
  float y;
  float z;
};

// I use this to select their element type in functions:
template <typename T>
using param_vector = std::conditional_t<std::is_same<std::remove_const_t<std::remove_reference_t<T>>, Vector3f64>::value, double, float>;

// This is the function I want to pull the return type from:
template <typename T>
T VectorVolume(const T x, const T y, const T z)
{
  return x * x + y * y + z * z;
}

template<class R, class... ARGS>
std::function<R(ARGS...)> make_func(R(*ptr)(ARGS...)) {
  return std::function<R(ARGS...)>(ptr);
}

// This function fails to compile:
template <typename T>
typename decltype(make_func(&VectorVolume<param_vector<T>>))::result_type func(const T& dir)
{
  return VectorVolume(dir.x, dir.y, dir.z);
}

int main() {
  const Vector3f64 foo{ 10.0, 10.0, 10.0 };

  std::cout << func(foo) << std::endl;
}
