I am trying to make a method where the user can provide an analytic gradient function if available, but if not it defaults to using a numeric gradient.
To that effect I tried the following:
template<typename V, typename S, S (*Fun)(const V&)> V NumericGradient(const V& p)
{
const S e = 1.0e-6;
return {
Fun(p + V(e, 0, 0)) - Fun(p - V(e, 0, 0)) / S(2) * e,
Fun(p + V(0, e, 0)) - Fun(p - V(0, e, 0)) / S(2) * e,
Fun(p + V(0, 0, e)) - Fun(p - V(0, 0, e)) / S(2) * e,
};
}
template<typename V, typename S = decltype(V()[0])>
std::vector<V> DualContouring(
S (*DistanceFunction)(const V&),
V (*GradientFunction)(const V&) = NumericGradient<V, S, decltype(DistanceFunction)>,
const S span = S(50),
const unsigned int resolution = 100)
{
return {};
}
The compiler however is failing with this message (after instantiating it):
terrain_generation.cpp
../Src/examples/TerrainGeneration/terrain_generation.cpp: In function ‘std::vector<_RealType> DualContouring(S (*)(const V&), V (*)(const V&), S, unsigned int) [with V = Eigen::Matrix<float, 3, 1>; S = float]’:
../Src/examples/TerrainGeneration/terrain_generation.cpp:362:63: error: no matches converting function ‘NumericGradient’ to type ‘class Eigen::Matrix<float, 3, 1> (*)(const class Eigen::Matrix<float, 3, 1>&)’
362 | [](const Eigen::Vector3f& v) { return v.dot(v) - 10; });
| ^
In file included from ../Src/Engine/Renderer/Renderer.hpp:24,
from ../Src/examples/TerrainGeneration/terrain_generation.cpp:32:
../Src/Engine/Geometry/DualContouring.hpp:97:56: note: candidate is: ‘template<class V, class S, S (* Fun)(const V&)> V NumericGradient(const V&)’
97 | template<typename V, typename S, S (*Fun)(const V&)> V NumericGradient(const V& p)
| ^~~~~~~~~~~~~~~
../Src/examples/TerrainGeneration/terrain_generation.cpp:362:63: note: when instantiating default argument for call to ‘std::vector<_RealType> DualContouring(S (*)(const V&), V (*)(const V&), S, unsigned int) [with V = Eigen::Matrix<float, 3, 1>; S = float]’
362 | [](const Eigen::Vector3f& v) { return v.dot(v) - 10; });
| ^
../Src/examples/TerrainGeneration/terrain_generation.cpp: In function ‘void GenerateTerrain(Gallery&)’:
../Src/examples/TerrainGeneration/terrain_generation.cpp:362:63: error: no matches converting function ‘NumericGradient’ to type ‘class Eigen::Matrix<float, 3, 1> (*)(const class Eigen::Matrix<float, 3, 1>&)’
In file included from ../Src/Engine/Renderer/Renderer.hpp:24,
from ../Src/examples/TerrainGeneration/terrain_generation.cpp:32:
../Src/Engine/Geometry/DualContouring.hpp:97:56: note: candidate is: ‘template<class V, class S, S (* Fun)(const V&)> V NumericGradient(const V&)’
97 | template<typename V, typename S, S (*Fun)(const V&)> V NumericGradient(const V& p)
| ^~~~~~~~~~~~~~~
make[1]: *** [TerrainGeneration.make:156: obj/Debug/TerrainGeneration/terrain_generation.o] Error 1
make: *** [Makefile:39: TerrainGeneration] Error 2
make: Leaving directory '/home/makogan/vkengine/Generated'
Traceback (most recent call last):
File "build.py", line 139, in <module>
main()
File "build.py", line 106, in main
raise Exception("Compilation failed.")
Exception: Compilation failed.
I am not sure what's wrong with the type definitions there. The instantiation of NumericGradient should be type compatible with the expected function.
This is how I am trying to call the stub:
auto contour = DualContouring<Eigen::Vector3f, float>(
[](const Eigen::Vector3f& v) { return v.dot(v) - 10; });
I am compiling with g++ 9.3 under linux.
Alternative problem
Ok I tried dropping the default arguments alltoghether and force the user to always pass the function pointer.
Somehow even this:
float (*Distance)(const Eigen::Vector3f&) = [](const Eigen::Vector3f& v) {
return v.dot(v) - 9;
};
auto contour = DualContouring<Eigen::Vector3f, float>(
Distance, NumericGradient<Eigen::Vector3f, float>, Distance);
Fails to compile with error:
error: no matches converting function ‘NumericGradient’ to type ‘class Eigen::Matrix<float, 3, 1> (*)(const class Eigen::Matrix<float, 3, 1>&)’
365 | Distance, NumericGradient<Eigen::Vector3f, float>, Distance);```
Why? The template declaration should be fine.