【问题标题】:How to unpack empty variadic template list如何解压空的可变参数模板列表
【发布时间】:2016-04-09 13:35:00
【问题描述】:

我阅读了this 的问题并认为它很有趣,所以我开始使用一些代码来看看是否可以让它工作,但我遇到了一个问题。

我的方法是使用函数式编程熟悉的头尾成语。但是,我找不到处理空可变参数模板列表的方法,这将是基本情况。

这是我的代码:

#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)

我该如何修正我的方法?

【问题讨论】:

  • 你是如何尝试转发声明的?
  • @Petr 编辑了问题。
  • 在前向声明中只保留可变参数(即删除T1T2)你不累吗?
  • 好吧,你的专业是错误的。 T1 和 T2 消失了。
  • 与您链接的问题不同,您的代码似乎假设调用者希望为每个后续类型对测试is_convertible。这是故意的吗?

标签: c++ c++11 metaprogramming c++14 variadic-templates


【解决方案1】:

你有两个问题。

首先,通过前向声明,您说您的模板总是至少接受两个参数(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,这对我来说似乎是正确的结果。

【讨论】:

  • 提供的两种解决方案都很好,但这个特别解决了空变量(即&lt;&gt;)。
【解决方案2】:

你的专业是错误的。 T1T2 消失了。部分专门用于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
}

Live on Coliru

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    • 2018-11-19
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多