c++ - 使用模板创建默认函数参数

标签 c++ templates compiler-errors template-meta-programming

我正在尝试创建一种方法,用户可以在其中提供分析梯度函数(如果可用),但如果不可用,则默认使用数字梯度。

为此,我尝试了以下方法:

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 {};
}

然而,编译器失败并显示此消息(在实例化之后):

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.

我不确定那里的类型定义有什么问题。 NumericGradient 的实例化应该与预期的功能类型兼容。

这就是我尝试调用 stub 的方式:

auto contour = DualContouring<Eigen::Vector3f, float>(
        [](const Eigen::Vector3f& v) { return v.dot(v) - 10; });

我在 linux 下用 g++ 9.3 编译。

替代问题

好的,我尝试完全删除默认参数并强制用户始终传递函数指针。

不知何故甚至这样:

    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);

编译失败:

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.

最佳答案

正在关注 Jarod42 explanation , NumericGradient 的第三个模板参数是一个非类型参数,而 decltype(DistanceFunction) 是一个类型。所以,我相信你想做的是使用 DistanceFunction,但是,正如他提到的,不能在这种情况下使用参数名称。

作为替代方案,您可以将函数指针模板参数“降级”为常规函数指针参数:

template<typename V, typename S> V NumericGradient(const V& p, S (*Fun)(const V&));

并传递它。

这是一个工作示例: https://godbolt.org/z/qhY938

作为另一种选择,您可以将 DistanceFunction 作为模板参数传递给 DualContouring

这是另一个工作示例: https://godbolt.org/z/EnaMjK

关于c++ - 使用模板创建默认函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65497659/

相关文章:

oracle - 触发器中的SQL IF ELSE语句

c++ - 一个类可以共享一个命名空间的名称吗?

c++ - 在 Windows 上使用 Gtest 和 Gmock

c++ - 当我使用模板时,编译器无法将函数的返回类型从 double 转换为 int

C 编译器无意义的错误?

xcode - 突然出现AppDelegate.h错误

C++ 指针运算 : alignment exception (0x801)

C++ 删除类成员 Char*

c++ - 如何在模板类中使用模板

c++ - 使用模板更改类型的解决方法