如何解压缩空的可变模板列表

How to unpack empty variadic template list

本文关键字:列表 解压缩      更新时间:2023-10-16

我读到这个问题,觉得它很有趣,所以我开始玩一些代码,看看是否能让它发挥作用,但我遇到了一个问题。

我的方法是使用函数式编程中熟悉的头尾习惯用法。然而,我找不到一种方法来处理一个空的可变模板列表,这将是基本情况。

这是我的代码:

#include <iostream>
#include <type_traits>
class A {};
class B : public A {};
class C {};
class D : public C {};
/*
// Forward declaration
template <typename T1, typename T2, typename... Args>
struct are_convertible;
*/
// There are no Args
template <>
struct are_convertible<> {
    static const bool value = true;
};
// Check if the first two elements are convertible then recurse on the rest
template <typename T1, typename T2, typename... Args>
struct are_convertible {
    static const bool value = std::is_convertible<T1, T2>::value && are_convertible<Args...>::value;
};
int main() {
    std::cout << std::boolalpha;
    std::cout << "Are convertible A->B and C->D: " << are_convertible<A, B, C, D>::value << std::endl; // Should be false
}

我目前收到一个状态为'are_convertible' is not a class template的错误,所以我尝试转发声明它,这导致了以下错误:

错误:模板参数数量错误(0,应至少为2)

我该如何修正我的方法?

您有两个问题。

首先,对于正向声明,您说您的模板总是接受至少两个参数(T1T2)。如果你想让你的结构不允许参数,你需要转发声明它只有可变参数:

template<typename... Args>
struct are_convertible;

其次,您的第二个定义不是部分专门化,而是一个完整的通用(新的)模板定义,它与前面的正向声明相矛盾。您需要的是部分专业化:

template <typename T1, typename T2, typename... Args>
struct are_convertible<T1, T2, Args...> {
                    //^^^^^^^^^^^^^^^^^

之后,您的代码工作:

class A {};
class B : public A {};
class C {};
class D : public C {};
template<typename... Args>
struct are_convertible;
// There are no Args
template <>
struct are_convertible<> {
    static const bool value = true;
};
// Check if the first two elements are convertible then recurse on the rest
template <typename T1, typename T2, typename... Args>
struct are_convertible<T1, T2, Args...> {
    static const bool value = std::is_convertible<T1, T2>::value && are_convertible<Args...>::value;
};
int main() {
    std::cout << std::boolalpha;
    std::cout << "Are convertible A->B and C->D: " << are_convertible<A, B, C, D>::value << std::endl;
    std::cout << "Are convertible B->A and D->C: " << are_convertible<B, A, D, C>::value << std::endl;
}

这将打印falsetrue,这对我来说似乎是一个正确的结果。

您的专业化是错误的。CCD_ 6和CCD_。部分专用于T1T2,这意味着没有为Args...留下其他参数。以下代码:

#include <iostream>
#include <type_traits>
class A {};
class B : public A {};
class C {};
class D : public C {};

// Forward declaration
template <typename T1, typename T2, typename... Args>
struct are_convertible;
// There are no Args
template <typename T1, typename T2>
struct are_convertible<T1, T2> {
    static const bool value = std::is_convertible<T1, T2>::value;
};
// Check if the first two elements are convertible then recurse on the rest
template <typename T1, typename T2, typename... Args>
struct are_convertible {
    static const bool value = std::is_convertible<T1, T2>::value && are_convertible<Args...>::value;
};
int main() {
    std::cout << std::boolalpha;
    std::cout << "Are convertible A->B and C->D: " << are_convertible<A, B, C, D>::value << std::endl; // Should be false
}

在Coliru上直播