模糊的递归模板功能

bre*_*att 8 c++ templates eigen c++11 eigen3

在C++ 11中,我需要递归地调用一个函数0,...,n(其中n是编译时常量).这是问题的结构,似乎存在致命缺陷:

#include "Eigen/Dense"

template<size_t i>
struct Int {
};

template<size_t d, typename C, typename X>
constexpr X eval(const C &c, const X &x, const Int<d> &, const Int<C::SizeAtCompileTime - 1 - d> &) {
    return 1;
}

template<size_t d, typename C, typename X, size_t i>
constexpr X eval(const C &c, const X &x, const Int<d> &, const Int<i> &) {
    return x * eval(c, x, Int<d>(), Int<i + 1>());
}

int main() {
    const size_t d = 1;
    const Eigen::Matrix<double, 1, 7> c = Eigen::Matrix<double,1,7>::Zero();
    const double x = 5;
    eval(c, x, Int<d>(), Int<0>());
}
Run Code Online (Sandbox Code Playgroud)

和完整的错误消息:

/usr/bin/cmake --build /mnt/c/Dropbox/clion/recursion/cmake-build-debug --target recursion -- -j 4
Scanning dependencies of target recursion
[ 50%] Building CXX object CMakeFiles/recursion.dir/main.cpp.o
/mnt/c/Dropbox/clion/recursion/main.cpp: In instantiation of 'constexpr X eval(const C&, const X&, const Int<d>&, const Int<i>&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double; long unsigned int i = 4ul]':
/mnt/c/Dropbox/clion/recursion/main.cpp:14:20:   recursively required from 'constexpr X eval(const C&, const X&, const Int<d>&, const Int<i>&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double; long unsigned int i = 1ul]'
/mnt/c/Dropbox/clion/recursion/main.cpp:14:20:   required from 'constexpr X eval(const C&, const X&, const Int<d>&, const Int<i>&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double; long unsigned int i = 0ul]'
/mnt/c/Dropbox/clion/recursion/main.cpp:21:34:   required from here
/mnt/c/Dropbox/clion/recursion/main.cpp:14:20: error: call of overloaded 'eval(const Eigen::Matrix<double, 1, 7>&, const double&, Int<1ul>, Int<5ul>)' is ambiguous
     return x * eval(c, x, Int<d>(), Int<i + 1>());
                    ^
/mnt/c/Dropbox/clion/recursion/main.cpp:8:13: note: candidate: constexpr X eval(const C&, const X&, const Int<d>&, const Int<((C:: SizeAtCompileTime - 1) - d)>&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double]
 constexpr X eval(const C &c, const X &x, const Int<d> &, const Int<C::SizeAtCompileTime - 1 - d> &) {
             ^
/mnt/c/Dropbox/clion/recursion/main.cpp:13:13: note: candidate: constexpr X eval(const C&, const X&, const Int<d>&, const Int<i>&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double; long unsigned int i = 5ul]
 constexpr X eval(const C &c, const X &x, const Int<d> &, const Int<i> &) {
             ^
/mnt/c/Dropbox/clion/recursion/main.cpp:15:1: error: body of constexpr function 'constexpr X eval(const C&, const X&, const Int<d>&, const Int<i>&) [with long unsigned int d = 1ul; C = Eigen::Matrix<double, 1, 7>; X = double; long unsigned int i = 4ul]' not a return-statement
 }
Run Code Online (Sandbox Code Playgroud)

我的理解是,在最后一行,x * eval(c, x, Int<d>(), Int<i + 1>());何时i+1 = n,然后将选择返回1的第一个函数,但编译器说调用是不明确的.有人可以解释一下原因吗?以及如何解决这个问题?

注意:我知道你不能部分专门化模板功能.我试图模仿行为,而不是重载.


编辑

似乎问题在于扩张C::SizeAtCompileTime.当我对该常量进行硬编码时,程序会编译.是否有一般的C++规则说明为什么会发生这种情况?或者是特定于特定的东西?

Sto*_*ica 6

一方面,模糊性的原因在于,您有两个功能模板,就部分排序而言同样好.当第一个重载的模板参数不是依赖值时(n在原始问题中),部分排序可以很好地决定它.但是C::SizeAtCompileTime依赖,因此部分排序不再能够解决问题.

但是,我们可以用SFINAE来解决这个问题.我们需要做的就是在i我们可能发生冲突时从重载集中删除第二个重载.这可以通过简单的方式完成std::enable_if:

template<size_t d, typename C, typename X, size_t i>
constexpr auto eval(const C &c, const X &x, const Int<d> &, const Int<i> &)
  -> typename std::enable_if<i != C::SizeAtCompileTime - 1 - d, X>::type {
    return x * eval(c, x, Int<d>(), Int<i + 1>());
}
Run Code Online (Sandbox Code Playgroud)