How to unpack an empty list of variation patterns

I read this question and thought it was interesting, so I started playing with some code to see if I could make it work, but I ran into a problem.

My approach is to use the head-tail idiom familiar to functional programming. However, I could not find a way to deal with an empty variational list of templates that would be basic.

Here is my code:

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

I am currently receiving an error message that indicates 'are_convertible' is not a class template, so I tried forwarding the declaration that gave this error:

error: incorrect number of template arguments (0, must be at least 2)

How can I fix my approach?

+4
2

.

-, , (T1 T2). , - :

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;
}

false true, .

+5

. T1 T2 . T1 T2, , 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

+1

Source: https://habr.com/ru/post/1622943/


All Articles