模板解析不清楚

问题描述 投票:0回答:1

我正在完成这篇文章中的练习https://www.slamecka.cz/posts/2021-03-17-cpp-metaprogramming-exercises-1/

首先,我要向作者表示衷心的感谢。这些问题非常有趣、具有挑战性且引人入胜。

问题的一部分给我带来了一些问题,我不太明白为什么。

/**
 * 18. Define Insert for Vector, it should take position, value and vector.
 * Don't worry about bounds.
 * Hint: use the enable_if trick, e.g.
 *   template<typename X, typename Enable = void> struct Foo;
 *   template<typename X> struct<std::enable_if_t<..something      about X..>> Foo {...};
 *   template<typename X> struct<std::enable_if_t<..something else about X..>> Foo {...};
 */

// Your code goes here:
// ^ Your code goes here

// static_assert(std::is_same_v<Insert<0, 3, Vector<4,5,6>>::type, Vector<3,4,5,6>>);
// static_assert(std::is_same_v<Insert<1, 3, Vector<4,5,6>>::type, Vector<4,3,5,6>>);
// static_assert(std::is_same_v<Insert<2, 3, Vector<4,5,6>>::type, Vector<4,5,3,6>>);
// static_assert(std::is_same_v<Insert<3, 3, Vector<4,5,6>>::type, Vector<4,5,6,3>>);

我开始解决这个问题,无视作者的提示。

这是我第一次尝试。

template <int P, int I, typename V> struct Insert;

template <int P, int I, int F, int... N> struct Insert<P, I, Vector<F, N...>> {
  using type = Prepend<F, typename Insert<P - 1, I, Vector<N...>>::type>::type;
};

template <int I, int... N> struct Insert<0, I, Vector<N...>> {
  using type = typename Prepend<I, Vector<N...>>::type;
};

作为此方法的错误消息,编译器抱怨歧义性

E:\problems\main.cpp(212,20): error: ambiguous partial specializations of 'Insert<0, 3, (anonymous namespace)::Vector<4, 5, 6>>'
[build]   212 |     std::is_same_v<Insert<0, 3, Vector<4, 5, 6>>::type, Vector<3, 4, 5, 6>>);
[build]       |                    ^
[build] E:\problems\main.cpp(163,49): note: partial specialization matches [with P = 0, I = 3, F = 4, N = <5, 6>]
[build]   163 | template <int P, int I, int F, int... N> struct Insert<P, I, Vector<F, N...>> {
[build]       |                                                 ^
[build] E:\problems\main.cpp(167,35): note: partial specialization matches [with I = 3, N = <4, 5, 6>]
[build]   167 | template <int I, int... N> struct Insert<0, I, Vector<N...>> 

然后我读了提示,心想,如果我只使用

std::conditional_t

会怎样?
template <int P, int I, typename V> struct Insert;

template <int P, int I, int F, int... N> struct Insert<P, I, Vector<F, N...>> {
  using type = std::conditional_t<
      P == 0, typename Prepend<I, Vector<N...>>::type,
      typename Prepend<F, typename Insert<P - 1, I, Vector<N...>>::type>::type>;
};

这次我收到了不同的错误消息

[build] E:\problems\main.cpp(178,36): error: implicit instantiation of undefined template '(anonymous namespace)::Insert<-3, 3, (anonymous namespace)::Vector<>>'
[build]   178 |       typename Prepend<F, typename Insert<P - 1, I, Vector<N...>>::type>::type>;
[build]       |                                    ^
[build] E:\problems\main.cpp(178,36): note: in instantiation of template class '(anonymous namespace)::Insert<-2, 3, (anonymous namespace)::Vector<6>>' requested here
[build] E:\problems\main.cpp(178,36): note: in instantiation of template class '(anonymous namespace)::Insert<-1, 3, (anonymous namespace)::Vector<5, 6>>' requested here
[build] E:\problems\main.cpp(222,20): note: in instantiation of template class '(anonymous namespace)::Insert<0, 3, (anonymous namespace)::Vector<4, 5, 6>>' requested here
[build]   222 |     std::is_same_v<Insert<0, 3, Vector<4, 5, 6>>::type, Vector<3, 4, 5, 6>>);
[build]       |                    ^
[build] E:\problems\main.cpp(173,44): note: template is declared here
[build]   173 | template <int P, int I, typename V> struct Insert;
[build]       |                                            ^

任何人都可以解释一下为什么我收到这些消息,它们为什么不同?

c++ c++11 templates std metaprogramming
1个回答
0
投票

代码失败是因为模板专业化一般太宽泛。你无法阻止这个

template <int I, int... N>
struct Insert<0, I, Vector<N...>> {
    using type = typename Prepend<I, Vector<N...>>::type;
};

还有这个

template <int P, int I, int F, int... N>
struct Insert<P, I, Vector<F, N...>> {
    using type = typename Prepend<F, typename Insert<P - 1, I, Vector<N...>>::type>::type;
};

来自匹配

P = 0
,即使第二个代码用于递归。如果
P = 0
那么
P = 0
。你必须手动处理它。

对此的一个适当的解决方案是使用

std::enable_if
来防止递归专门化在最终达到
P == 0
 的情况下与 
P = 0

匹配。
// forward declaration of Insert with std::enable_if
template <int P, int I, typename V, typename Enable = void>
struct Insert;

// specialization for P > 0 for recursion
template <int P, int I, int F, int... N>
struct Insert<P, I, Vector<F, N...>, std::enable_if_t<(P > 0)>> {
    using type = typename Prepend<F, typename Insert<P - 1, I, Vector<N...>>::type>::type;
};
© www.soinside.com 2019 - 2024. All rights reserved.