Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;专门化中的多个模板参数包_C++_Variadic Templates_Template Specialization - Fatal编程技术网

C++ C++;专门化中的多个模板参数包

C++ C++;专门化中的多个模板参数包,c++,variadic-templates,template-specialization,C++,Variadic Templates,Template Specialization,我在玩弄参数包,得到了一些我无法解释的行为(据我理解,这应该是有效的) 我有一个模板结构,它采用一种类型,并使用两个参数包()进行专门化: #包括 模板结构伪{}; 模板结构多重{}; 模板 结构正好是_one _not _0:std::false _type{}; 模板 结构正好是\u 1\u不是\u 0 < 倍数 < 笨蛋。。。, 笨蛋, 笨蛋。。。 >, 标准:布尔_常数 >:std::true\u类型 {}; 模板 constexpr bool justice_one_not_0_v=j

我在玩弄参数包,得到了一些我无法解释的行为(据我理解,这应该是有效的)

我有一个模板结构,它采用一种类型,并使用两个参数包()进行专门化:

#包括
模板结构伪{};
模板结构多重{};
模板
结构正好是_one _not _0:std::false _type{};
模板
结构正好是\u 1\u不是\u 0
<
倍数
<
笨蛋。。。,
笨蛋,
笨蛋。。。
>,
标准:布尔_常数
>:std::true\u类型
{};
模板
constexpr bool justice_one_not_0_v=justice_one_not_0::value;
使用d0=假人;
使用d1=假人;
静态断言(确切地说不是0);
静态断言(确切地说不是0);
静态断言(确切地说不是0);
静态断言(确切地说不是0);
静态断言(!正好一个非0个);
静态断言(!正好一个非0个);
静态断言(!正好一个非0个);
静态断言(!正好一个非0个);
静态断言(!正好一个非0个);
静态断言(!正好一个非0个);
静态断言(!正好一个非0个);
前四个断言失败。为什么?专业人员应该能够发现这些病例

相比之下,以下代码按预期工作():

#包括
模板
结构多单元包
{

静态void f(){std::cout在第二种情况下,您要求编译器在不同的类型中匹配包(有一对
Ts1
的元组和一对
Ts2
),这是明确无误的

在您的第一个示例中,两个包都在同一个参数包中使用,由第三种类型分隔。我理解您为什么希望它工作,但显然编译器(gcc和clang)拒绝完全匹配前缀包

在您的特定情况下,它实际上在一些情况下是不明确的:因为V是一个参数,它也可能是0,这使得它在匹配
d0
序列时不明确。无论如何,我尝试过,即使使用常量1也不能解决问题。您必须自己去掉前缀

#include <type_traits>
template<class, int> struct dummy{};
template<class...> struct multiple{};

template<class T, class = void> // <-- was this supposed to be an enabler?
struct exactly_one_not_0 : std::false_type {};

template<class Ts, class...RTs, int V>
struct exactly_one_not_0
<
    multiple
    <
        dummy<Ts, V>,
        dummy<RTs, 0>...
    >,
    std::enable_if_t<V!=0>
> : std::bool_constant<V>
{};

template<class LT, class...RDummies>
struct exactly_one_not_0
<
    multiple
    <
        dummy<LT, 0>,
        RDummies...
    >
> : exactly_one_not_0<multiple<RDummies...>>
{};

template<class T>
constexpr bool exactly_one_not_0_v = exactly_one_not_0<T>::value;

using d0 = dummy<int,0>;
using d1 = dummy<int,1>;

static_assert(exactly_one_not_0_v<multiple<d1>>);
static_assert(exactly_one_not_0_v<multiple<d1,d0>>);
static_assert(exactly_one_not_0_v<multiple<d0,d1>>);
static_assert(exactly_one_not_0_v<multiple<d0,d1,d0>>);

static_assert(!exactly_one_not_0_v<multiple<>>);
static_assert(!exactly_one_not_0_v<multiple<d0>>);
static_assert(!exactly_one_not_0_v<multiple<d0,d0>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d0,d1,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d0,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d1,d0>>);

int main()
{
    return 0;
}

使用
multiple
,你会得到模棱两可的推论。是的,
template
应该是一个启用/禁用开关(尽管我没有使用void和enable\u if,这有点搞砸了)。我希望我能阻止你发布的递归解决方案。我的主要问题是为什么它不匹配(例如:它是一个bug还是标准中的某个东西).@wsxedcrfv抱歉。我和你一样懒散,不看标准。我认为有问题的条款是17.5.5-8.4,其中规定“在类模板部分专用化的参数列表中,适用以下限制:[…]如果参数是包扩展,它应该是模板参数列表中的最后一个参数。”.我会将其解释为仅适用于论证列表的第一级(即不适用于您的案例),但看起来我错了。
    #include <iostream>
    template<class T>
    struct multi_pack
    {
          static void f() {std::cout << "base case\n";}
    };

    template<class...Ts1, class...Ts2>
    struct multi_pack<std::pair<std::tuple<Ts1...>, std::tuple<Ts2...>>>
    {
        using T = std::pair<std::tuple<Ts1...>, std::tuple<Ts2...>>;
        static void f() {std::cout << "special case\n";}
    };
#include <type_traits>
template<class, int> struct dummy{};
template<class...> struct multiple{};

template<class T, class = void> // <-- was this supposed to be an enabler?
struct exactly_one_not_0 : std::false_type {};

template<class Ts, class...RTs, int V>
struct exactly_one_not_0
<
    multiple
    <
        dummy<Ts, V>,
        dummy<RTs, 0>...
    >,
    std::enable_if_t<V!=0>
> : std::bool_constant<V>
{};

template<class LT, class...RDummies>
struct exactly_one_not_0
<
    multiple
    <
        dummy<LT, 0>,
        RDummies...
    >
> : exactly_one_not_0<multiple<RDummies...>>
{};

template<class T>
constexpr bool exactly_one_not_0_v = exactly_one_not_0<T>::value;

using d0 = dummy<int,0>;
using d1 = dummy<int,1>;

static_assert(exactly_one_not_0_v<multiple<d1>>);
static_assert(exactly_one_not_0_v<multiple<d1,d0>>);
static_assert(exactly_one_not_0_v<multiple<d0,d1>>);
static_assert(exactly_one_not_0_v<multiple<d0,d1,d0>>);

static_assert(!exactly_one_not_0_v<multiple<>>);
static_assert(!exactly_one_not_0_v<multiple<d0>>);
static_assert(!exactly_one_not_0_v<multiple<d0,d0>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d0,d1,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d0,d1>>);
static_assert(!exactly_one_not_0_v<multiple<d1,d1,d0>>);

int main()
{
    return 0;
}
template<class T>
struct exactly_one_not_0 : std::false_type {};

template<class Enable, class... Ts> // <-- was this supposed to be an enabler?
struct exactly_one_not_0_impl : std::false_type {};

template<class... Ts>
struct exactly_one_not_0<multiple<Ts...>>
    : exactly_one_not_0_impl<void, Ts...>
{};

template<class Ts, class...RTs, int V>
struct exactly_one_not_0_impl
<
    std::enable_if_t<V!=0>,
    dummy<Ts, V>,
    dummy<RTs, 0>...
> : std::bool_constant<V>
{};

template<class LT, class...RDummies>
struct exactly_one_not_0_impl
<
    void,
    dummy<LT, 0>,
    RDummies...
> : exactly_one_not_0_impl<void, RDummies...>
{};