与模板的歧义

时间:2017-10-13 22:03:49

标签: c++ c++11 templates variadic-templates template-meta-programming

有人可以解释为什么以下因为含糊不清而无法遵守

#include <tuple>

template <typename, typename, int> struct foo;

template <template <typename...> class P, typename... Ts, typename... Us, int I>
struct foo<P<Ts...>, std::tuple<P<Us...>>, I> : foo<P<Ts...>, std::tuple<P<Us...>>, I-1> {};

template <template <typename...> class P, typename... Ts, typename... Us>
struct foo<P<Ts...>, std::tuple<P<Us...>>, 0> {};

template <typename...> struct P;

int main() {
    foo<P<int, bool, char>, std::tuple<P<>>, 5> a;
}

但是,如果我将std::tuple替换为P,则会消除歧义。如果我将P<Ts...>P<Us...>替换为名为Pack的简单类型,也会将其删除。我正在使用GCC 7.2。当然,foo<P<int, bool, char>, std::tuple<P<>>, 0>会出现歧义。如果我从foo定义中删除第一个模板,也会删除歧义。

这是我的非简化代码(好吧,减少了大约10%)。我上面简化的代码显然可以通过切换专业化的顺序来解决。下面,切换订单不起作用。

#include <tuple>

template <typename Pack, typename OutputPack, std::size_t...> struct foo;

template <template <typename...> class P, typename First, typename... Rest, typename... Ts, typename... Packs, std::size_t I, std::size_t... Is>
struct foo<P<First, Rest...>, std::tuple<P<Ts...>, Packs...>, I, Is...> :
     foo<P<Rest...>, std::tuple<P<Ts..., First>, Packs...>, I-1, Is...> {};

template <template <typename...> class P, typename First, typename... Rest, typename... Ts, typename... Packs, std::size_t I, std::size_t J, std::size_t... Is>
struct foo<P<First, Rest...>, std::tuple<P<Ts...>, Packs...>, 0, I, J, Is...> : 
     foo<P<Rest...>, std::tuple<P<First>, Packs..., P<Ts...>>, I-1, J, Is...> {};

template <template <typename...> class P, typename First, typename... Rest, typename... Ts, typename... Packs, std::size_t Last>
struct foo<P<First, Rest...>, std::tuple<P<Ts...>, Packs...>, 0, Last> {};

template <typename...> struct P;

int main() {
    foo<P<int, bool, char, int, long, bool>, std::tuple<P<>>, 1,2,1> a;
}

但是,将std::tuple替换为P会因某种原因(再次)解决问题。

1 个答案:

答案 0 :(得分:1)

尝试切换特化顺序:在零版本之前,接下来是通用整数版本。

template <typename, typename, int> struct foo;

template <template <typename...> class P, typename... Ts, typename... Us>
struct foo<P<Ts...>, std::tuple<P<Us...>>, 0> {};

template <template <typename...> class P, typename... Ts, typename... Us, int I>
struct foo<P<Ts...>, std::tuple<P<Us...>>, I> : foo<P<Ts...>, std::tuple<P<Us...>>, I-1> {};

我的clang ++(3.8.1)编译您的原始代码没有问题,但我的g ++(6.3.0)给出了几个错误,第二个是

tmp_002-11,14,gcc,clang.cpp:21:8: error: invalid use of incomplete type ‘struct foo<P<int, bool, char>, std::tuple<P<> >, 0>’
 struct foo<P<Ts...>, std::tuple<P<Us...>>, I> : foo<P<Ts...>, std::tuple<P<Us...>>, I-1> {};
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我不知道谁是对的:g ++或clang ++。

但是g ++抱怨通用整数特化调用(I==1)与I == 0的专门化使这个专业化“不完整”。

如果您首先放置I == 0版本,则不再完整(从其他专业化的角度来看)。

- 编辑 -

关于你的“非简化代码”,问题看起来是一样的(仅适用于g ++)但是,在这种情况下,你无法解决改变专业化顺序的问题,因为以下两个专业化

template <template <typename...> class P, typename First, typename... Rest,
          typename... Ts, typename... Packs, std::size_t I, std::size_t... Is>
struct foo<P<First, Rest...>, std::tuple<P<Ts...>, Packs...>, I, Is...> 
   : foo<P<Rest...>, std::tuple<P<Ts..., First>, Packs...>, I-1, Is...>
 { };

template <template <typename...> class P, typename First, typename... Rest,
          typename... Ts, typename... Packs, std::size_t I, std::size_t J,
          std::size_t... Is>
struct foo<P<First, Rest...>, std::tuple<P<Ts...>, Packs...>, 0, I, J, Is...>
   : foo<P<Rest...>, std::tuple<P<First>, Packs..., P<Ts...>>, I-1, J, Is...>
{ };

相互依赖(继承)